Filter와 Interceptor?

Interceptor와 Filter?

Interceptor

Interceptor는 말 그대로 무언가를 낚아 채가는 놈을 의미하는 말이다. (여기서 무언가란 오고가는 요청을 말한다.) InterceptorDispatcherServlet가 컨트롤러를 호출하기 전과 후에 요청과 응답을 참조하거나 변경할 수 있는 일종의 필터를 말한다.


Interceptor의 구현

Interceptor는 주로 HandlerInterceptor 인터페이스를 구현한 클래스들을 말한다. HandlerInterceptor에는 아래와 같이 세 개의 메소드가 정의되어 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface HandlerInterceptor {

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

    void postHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception;

    void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception;

}
  • preHandle() : 컨트롤러가 호출되기 전에 실행된다. handler 파라미터는 handler mapping이 찾아 준 컨트롤러 빈 오브젝트다. 주로 요청을 로그로 남기거나 요청을 변경하는 역할로 쓰인다.
  • postHandle() : 컨트롤러를 실행하고 난 후에 실행된다. ModelAndView 타입의 인자를 파라미터로 받아 컨트롤러 작업 결과를 참조하거나 조작할 수 있다.
  • afterCompletion() : 모든 뷰에서 모든 작업이 마무리 된 이후에 실행되는 메소드이다. 주로 사용한 리소스를 반환해주는 역할로 많이 사용된다.

위 메소드들의 호출 순서는 preHandle() -> postHandle() -> afterCompletion() 순으로 이루어진다. 메소드 실행 중간에 에러가 발생할 경우에는 다음 메소드는 실행되지 않는다.


Interceptor의 적용
1
2
3
4
5
6
7
8
9
10
//servlet-context.xml

<mvc:interceptors>
    <mvc:interceptor>
       <mvc:mapping path="/api1/*" />  
       <mvc:mapping path="/api2/*" />  
       <mvc:mapping path="/api3/*" />  
       <bean class="com.xxxx.xxxxx.interceptor.인터셉터클래스" />
     </mvc:interceptor>
</mvc:interceptors>

호출되는 URL을 <mvc:mapping path=""/>로 적으면 위의 URL이 호출될 경우에 빈으로 등록한 Interceptor를 먼저 거치게된다.



Filter

FilterInterceptor가 호출되기 이전, 그리고 DispatcherServlet에 요청이 들어오기 전에 먼저 거치게 되는 클래스를 말한다. Filter는 일반적으로 서블릿 컨테이너에서 제어하기 때문에 web.xml에서 정의되어야 하며, Spring application에서 관리하는 빈을 DI(Dependency Injection)로 받을 수 없다.


Filter의 구현

FilterFilter 인터페이스를 구현하여 사용할 수 있는데, Filter에는 아래와 같은 세 개의 메소드가 정의되어 있다.

doFilter() 메소드가 필터의 주된 기능을 하는 메소드로써, 메소드 내부에 있는 chian.doFilter(request, response);는 정의되어 있는 다른 필터를 호출하는 역할을 한다. 따라서 DispatcherServlet이 호출되기 전에 요청을 변경하고 싶은 경우에는 chain.doFilter(request, response);함수가 호출되기 이전에 구현을 해놓으면 된다 (//수행 전 행동 정의 부분). 모든 필터가 호출이 된 다음에는 DispatcherServlet이 마지막으로 호출된다.

모든 Controller들이 호출되고 뷰가 완성이 된 다음에 필터를 빠져나오면서 //수행 후 행동 정의 부분에 구현된 동작이 실행된다. 따라서 이곳에는 응답을 변경하는 코드가 들어가면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface Filter {
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        //수행 전 행동 정의

        chain.doFilter(request, response); // 그 다음 필터를 호출.

        //수행 후 행동 정의
    }

    public void init() {
    }

    public void destroy() {
    }
}


Filter의 적용

FilterDispatcherServlet이 호출되기 이전에 행동이 정의가 되어야 하기 때문에 web.xmlFilter에 대한 정의가 되어있어야 한다.

1
2
3
4
5
6
7
8
<filter>
    <filter-name>필터이름</filter-name>
    <filter-class>com.changpd.test.filter.필터클래스</filter-class>
</filter>
<filter-mapping>
    <filter-name>필터이름</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>



Filter와 Interceptor의 호출 시점

위의 내용들 처럼 FilterInterceptor모두 Controller가 호출되기 이전이나 이후에 수행되는 클래스들을 의미한다. 그렇다면 FilterInterceptor 중 어느 것이 먼저 호출되거나 나중에 호출될까? 아래의 그림을 보자.

89101625_26c5be9fd9.jpg

FilterDispatcherServlet이 호출되기 이전에 먼저 호출되어 요청을 변경하고 그 이후에 DispatcherServlet을 호출한다. 호출된 DispatcherServletHandlerMappingInterceptor를 호출한다. 그 이후에 Controller를 호출하여 로직은 처리하고 관련된 모든 행동의 끝난 이후에 Interceptor가 다시 호출된다. 그 이후에 View와 관련된 부분을 처리하기 위해 ViewResolver가 호출되고 View를 생성, 반환해준다. 모든 행동이 끝난 이후에 DispatcherServlet, Filter 순으로 응답이 나오게 된다.