필터와 인터셉터

김성혁·2022년 9월 18일
0

공통 관심사를 해결할 수 있는 방법에는 서블릿 필터 또는 스프링 인터셉터 그리고 스프링 AOP가 존재한다.

필터

  • Servlet이 제공하는 기능
  • 리소스에 대한 요청(서블릿 또는 정적 콘텐츠)이나 리소스의 응답 혹은 둘 다에 대해 필터링 작업을 수행하는 객체

필터 사용의 예

1) Authentication Filters

2) Logging and Auditing Filters

3) Image conversion Filters

4) Data compression Filters

5) Encryption Filters

6) Tokenizing Filters

7) Filters that trigger resource access events

8) XSL/T filters

9) Mime-type chain Filter

필터 흐름

HTTP 요청 → WAS → 필터 → 서블릿 → 컨트롤러

필터 체인

HTTP 요청 → WAS → 필터1 → 필터2 → 필터3 → 서블릿 → 컨트롤러

public interface Filter {

    public default void init(FilterConfig filterConfig) throws ServletException {}
  
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;

    public default void destroy() {}
}

필터 인터페이스를 구현하고 등록하면 서블릿 컨테이너가 필터를 싱글톤 객체로 생성하고, 관리

  • init() : 필터 초기화 메서드, 서블릿 컨테이너가 생성될 때 호출된다.
  • doFilter() : 고객의 요청이 올 때마다 해당 메서드가 호출된다. 필터의 로직을 구현하면 된다.
  • destroy() : 필터 종료 메서드, 서블릿 컨테이너가 종료될 때 호출된다.

chain.doFilter(request, response) : 이 부분이 가장 중요하다. 다음 필터가 있으면 필터를 호출하고, 필터가 없으면 서블릿을 호출한다. 만약 이 로직을 호출하지 않으면 다음 단계로 진행되지 않는다.

필터 등록 방법

  • @Component (모든 URL에 적용)
  • @WebFilter + @ServletComponentScan (특정 URL 패턴에만 적용 가능)
    • 스프링 컨테이너가 아닌 서블릿 컨테이너에 등록됨.
  • FilterRegistrationBean을 이용한 등록(순서와 URL 지정 등 옵션이 많은 것이 특징)

필터에는 다음에 설명할 스프링 인터셉터는 제공하지 않는, 아주 강력한 기능이 있는데
chain.doFilter(request, response); 를 호출해서 다음 필터 또는 서블릿을 호출할 때 request , response 를 다른 객체로 바꿀 수 있다. ServletRequest , ServletResponse 를 구현한 다른 객체를 만들어서 넘기면 해당 객체가 다음 필터 또는 서블릿에서 사용된다. 잘 사용하는 기능은 아니니 참고만 해두자.


인터셉터

  • 스프링이 제공하는 기능

스프링 인터셉터 흐름

HTTP 요청 → WAS → 필터 → 서블릿 → 스프링 인터셉터 → 컨트롤러

스프링 인터셉터 체인

HTTP 요청 → WAS → 필터 → 서블릿 → 인터셉터1 → 인터셉터2 → 컨트롤러

public interface HandlerInterceptor {

	default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return true;
	}

	default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable ModelAndView modelAndView) throws Exception {
	}

	default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable Exception ex) throws Exception {
	}

}

인터셉터는 컨트롤러 호출 전(preHandle), 호출 후(postHandle), 요청 완료 이후(afterCompletion)와 같이 단계적으로 세분화 되어 있다.

인터셉터는 서블릿 다음에 호출되기 때문에 어떤 컨트롤러가 호출되는지 호출 정보도 받을 수 있다. 그리고 어떤 modelAndView가 반환되는지 응답 정보도 받을 수 있다.

정상 흐름

  • preHandle : 컨트롤러 호출 전에 호출된다. (더 정확히는 핸들러 어댑터 호출 전에 호출된다.) preHandle 의 응답값이 true 이면 다음으로 진행하고, false 이면 더는 진행하지 않 는다. false인 경우 나머지 인터셉터는 물론이고, 핸들러 어댑터도 호출되지 않는다. 그림에서 1번에서 끝이 나버린다.
  • postHandle : 컨트롤러 호출 후에 호출된다. (더 정확히는 핸들러 어댑터 호출 후에 호출된다.)
  • afterCompletion : 뷰가 렌더링 된 이후에 호출된다.

예외가 발생시

  • preHandle : 컨트롤러 호출 전에 호출된다.
  • postHandle : 컨트롤러에서 예외가 발생하면 postHandle 은 호출되지 않는다.
  • afterCompletion : afterCompletion 은 항상 호출된다. 이 경우 예외( ex )를 파라미터로 받아서 어떤 예외가 발생했는지 로그로 출력할 수 있다.

인터셉터 등록 방법

  • WebConfig 클래스의 addInterceptors 메서드 오버라이드를 통한 등록
    - 인터셉터를 적용하거나 하지 않을 부분은 addPathPatterns 와 excludePathPatterns 에 작성하면 된다.

인터셉터는 스프링 MVC 구조에 특화된 필터 기능을 제공한다고 이해하면 된다. 스프링 MVC를 사용하고, 특별히 필터를 꼭 사용해야 하는 상황이 아니라면 인터셉터를 사용하는 것이 더 편리하다.

0개의 댓글