초이로그

서블릿 필터 & 스프링 인터셉터 본문

우아한테크코스/테코톡 정리

서블릿 필터 & 스프링 인터셉터

수연초이 2022. 11. 15. 17:43

공통 관심사항(대부분의 비즈니스 로직에서 관심을 가지는 부분)을 한번에 추출해서 처리한다면 코드를 간결하게 작성할 수 있다.

관심사항은 Spring AOP를 사용할 수도 있지만, 웹과 관련된 관심사항이라면 필터나 인터셉터를 이용하는 것이 좋다. 파라미터에 ServletRequest와 ServletResponse를 제공하므로 URL 정보나 HTTP 헤더를 직접 조작할 수 있기 때문이다.

 

서블릿 필터

정의

Filter는 J2EE 표준 스펙으로 Servlet API 2.3부터 등장하였고 Dispatcher Servlet에 요청이 전달되기 전, 후에 부가 작업을 처리하는 객체이다.

요청이 들어올 때는 서블릿 전에 필터가 실행되고, 응답을 보낼 때는 서블릿이 실행 후에 필터가 동작한다. 필터 인터페이스를 구현(implementation)하고 등록(Bean)하면 필터가 등록된다.

 

제공하는 메서드

public interface Filter {
	
    init(final FilterConfig filterConfig);
    
    doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
    
    destroy();
}
  • init
    • 선택적으로 오버라이딩
    • 필터가 생성될 때 단 한번 호출
    •  FilterConfig: Filter 정보를 담고 있는 객체. XML로 등록하면, XML의 정보가 FilterConfig 객체에 담겨서 초기화 시 사용 가능
  • doFilter
    • 구현 필수. 분리된 관심사항 구현
    • 요청이 들어올 때마다 호출됨. 직접적인 인증이나 부가적인 작업 처리 가능
    • ServletRequest, ServletResponse 파라미터로 HTTP 정보 읽기 가능
    • FilterChain: Filter가 여러개 모여 형성된 체인. doFilter를 호출해야 다음 필터나 다음 단계로 넘어갈 수 있다
  • destroy
    • 선택적으로 오버라이딩
    • 필터가 소멸될 때 단 한번 호출(WAS가 닫힐 때)

필터 등록 방법

  • @Component: 모든 URL에 적용
  • @WebFilter + @ServletComponentScan
    • @WebFilter: URL 패턴으로 URL 분류 가능
    • @ServletComponentScan: 필터 등록. @ComponentScan처럼 빈을 등록. 대상은 웹 필터나 웹 서블릿, 웹 리스너. 서블릿 객체를 서블릿컨테이너 위에 올린다
    • 스프링 컨테이너가  등록되는 것이 아닌, 서블릿 컨테이너(스프링을 띄운 WAS는 앞 단의 Servlet Container와 뒷 단의 Spring Container로 구성)에 등록되기 때문에 @Order가 동작하지 않음
    • 웹 필터 속성에도 순서를 지정해주는 속성이 없기 때문에 순서 지정 불가
  • FilterRegistrationBean: 객체를 만들고 필터를 등록하고 순서 지정, url 패턴 지정 가능. 옵션이 가장 많은 방식

동작 방식

1. FilterChain의 doFilter 실행

2. pos가 0으로 초기화 ➡️ pos가 0에 위치한 Filter의 doFilter 실행

3. pos가 0에 위치한 Filter에서 chain.doFilter 호출 ➡️ ApplicationFilterChain 호출

4. pos를 증가시키면서 같은 방법으로 다음 필터 수행

따라서 chain.doFilter를 반드시 명시해야한다

 

스프링 인터셉터

정의

인터셉터는 Spring이 제공하는 기술로, Dispatcher Servlet이 컨트롤러를 호출하기 전/후 요청에 대해 부가적인 작업을 처리하는 객체다.

 

제공하는 메서드

default boolean preHandle(HttpServletRequest request, HttpServeletResponse response, Object handler) throws Exception;

default void postHandle(HttpServletRequest request, HttpServeletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception;

default void afterCompletion(HttpServletRequest request, HttpServeletResponse response, Object handler, @Nullable Exception ex) throws Exception;
  • preHandle
    • Handler가 실행되기 전에 실행되는 메서드
    • 주로 비즈니스 로직에서 공통적으로 처리할 사항 구현 가능
  • postHandle
    • Handler가 실행된 이후에 실행되는 메서드
    • ModelAndView 인자를 통해 추가적인 작업 가능
  • afterCompletion
    • Handler가 실행된 이후에 실행되는 메서드
    • Exception 인자를 통해 비즈니스 로직에서 발생한 예외에 대한 처리 가능
    • 리소스들을 정리할 때도 사용가능
  • 메서드 세개 모두 default 메서드이므로 사용하고자 하는 사람이 필요한 것을 선택해서 사용 가능

인터셉터 등록 방법

@Configuration
public class WebConfig implements WebMvcConfigurer {

	private final LoginInterceptor loginInterceptor;
    
        public WebConfig(LoginInterceptor loginInterceptor) {
            this.loginInterceptor = loginInterceptor;
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) { // 인터셉터 추가
            registry.addInterceptors(loginInterceptor)
                .addPathPatterns("/**") // 모든 uri 요청에 대해 인터셉터 적용
                .excludePathPatterns("/signup", "/login"); // 인터셉터 적용하지 않는 uri
        }
}

WebMvcConfigurer 인터페이스를 구현한 클래스 내부에서 addInterceptors() 메서드를 오버라이드해서 추가해서 사용

 

호출 시점

핸들러 조회 ➡️ 알맞은 핸들러 어댑터 가져옴 ➡️ preHandle ➡️ 핸들러 어댑터를 통해 핸들러(ex. 컨트롤러. 즉 비즈니스 로직) 실행 ➡️ postHandle ➡️ view 관련 처리 ➡️ afterCompletion

 

동작방식

1. 핸들러 조회

2. 핸들러를 처리할 수 있는 핸들러 어댑터 조회

3. applyPreHandle메서드에서 인터셉터들의 preHandle 메서드를 호출

  • 인터셉터가 등록된 순서대로 preHandle이 호출된다

4. 모든 preHandle이 성공적으로 수행되면 HandlerAdapter를 통해 핸들러가 실행됨(비즈니스 로직)

5. applyPostHandle메서드에서 인터셉터들의 postHandle 메서드를 호출

  • 인터셉터가 등록된 역순서대로 postHandle이 호출된다

6. processDispatchResult에서 view관련 로직 수행

  • ViewResolver를 호출하고 view를 반환받고, HTML 응답하는 과정

7. afterCompletion 메서드를 통해 역순으로 인터셉터의 afterCompletion을 수행

 

필터와 인터셉터 차이

필터 인터셉터
자바 표준 스펙 스프링이 제공하는 기술
다음 필터를 실행하기 위해 개발자가 명시적으로 작성해줘야한다 다음 인터셉터를 실행하기 위해 개발자가 신경써야하는 부분이 없다
ServletRequest, ServletResponse를 필터 체이닝 중간에 새로운 객체로 바꿀 수 있다 ServletRequest, ServletResponse를 인터셉터 체이닝 중간에 새로운 객체로 바꿀 수 없다(request, response 객체내부는 변경 가능)
필터에서 예외가 발생하면 @ControllerAdvice에서 처리하지 못한다
예외를 잡거나 상태코드 변경 불가
(@ControllerAdvice 영역 밖)
인터셉터에서 예외가 발생하면 @ControllerAdvice에서 처리가 가능하다
예외를 잡거나 상태코드 변경 가능
(DispatcherServlet에서 호출되므로 관리 영역안에 존재하므로)

언제 사용해야할까?

- 옛날에는 서블릿 필터를 스프링 빈으로 등록할 수 없었다.. 변화되고 발전되면서 서블릿 필터를 빈으로 관리할 수 있게 되었다..

- 스프링에서 기본적으로 제공하는 필터들의 인코딩, Post, put, delete 등 http 메서드를 wrapping해주는 공통점이 있다. Spring 관련이 아닌 전반적인 웹과 관련된 기술

- 인터셉터에서는 ModelAttribute 바인딩 속성을 request에 넣어주거나 스프링에 관련된 기술을 작업한다.

기준을 잘 정해서 사용하자!

 

 

 

'우아한테크코스 > 테코톡 정리' 카테고리의 다른 글

데이터베이스 락  (2) 2022.11.09
JDK Dynamic Proxy vs CGLIB Proxy  (3) 2022.10.18
Spring AOP  (0) 2022.10.14
인덱스  (0) 2022.10.14
CI/CD와 무중단 배포  (0) 2022.10.09