본문 바로가기

Spring

[Spring] Interceptor와 ServletFilter의 차이

ServletFilter

SerlvetFilter는 서블릿 스펙에서 제공하는 서블릿 전체에 공통 기능을 추가할 수 있는 기능으로 DispatcherServlet 앞에서 사용자의 요청과 응답을 처리할 수 있다. ServletFilter는 여러 개도 등록이 가능하며 특정 URI에만 필터 기능을 걸 수 있도록 설정할 수도 있다.

 

ServletFilter 구현체를 만드려면 javax.servlet.Filter 인터페이스를 구현해야 한다.

public interface Filter {

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

}

init()

웹 애플리케이션이 시작했을 때 서블릿 필터를 초기화하는 메서드이다. 메서드 인자로 FilterConfig를 받으며, 서블릿 필터를 설정하는 단계에서 설정한 파라미터나 서블릿 필터 이름 등이 포함되어 있다.

doFilter()

ServletFilter의 핵심 기능으로 필터링 역할을 수행한다. ServletRequest, ServletResponse, FilterChain을 인자로 받으며 ServletRequest와 ServletResponse 인자를 사용하여 사용자의 요청 메시지나 응답 메시지의 데이터를 처리하고 FilterChain 인자를 사용해 다음 로직을 계속해서 실행할 수 있다. 만약 FilterChain 클래스의 doFilter() 메서드를 호출했을 때 더이상 수행할 로직이 없다면 DispatcherServlet이 실행된다.

destroy()

웹 애플리케이션이 종료될 때 호출 되는 메서드로 서블릿 필터를 종료한다. 서블릿 필터의 기능을 정리하거나 종료하는 코드를 구현한다.

Interceptor

Interceptor는 스프링 웹 MVC 프레임워크에서 제공하는 기능으로 표준 스펙이 아니라 스프링 프레임워크에서만 사용할 수 있다. 구조상 스프링 프레임워크 내부, 즉 DispatcherServlet 뒤에서 동작한다. 또한 ServletFilter와 마찬가지로 특정 URI에만 Interceptor 기능을 설정할 수 있다.

 

Interceptor가 동작하는 방식은 가장 먼저 DispatcherServlet이 사용자 요청을 받으면 HandlerMapping 컴포넌트에 질의하여 어떤 컨트롤러 클래스의 메서드에 사용자 요청을 전달할지 찾는다. 그런 다음 사용자 요청에 적합한 Interceptor를 찾아 DispatcherServlet의 응답 객체인 HandlerExecutionChain에 응답하고 HandlerExcecutionChain에 등록된 Interceptor를 모두 거치게 되면 Controller가 실행된다.

 

HandlerInterceptor 인터페이스는 세 개의 디폴트 메서드를 제공한다.

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()

preHandle() 메서드는 DispatcherServlet이 컨트롤러의 메서드를 실행하기 전에 실행되는 메서드로 인자로 받는 HttpServletRequest와 HttpServletResponse를 사용하여 사용자의 요청, 응답 메시지의 데이터를 처리할 수 있다. Object 인자는 컨트롤러 클래스의 핸들러 메서드를 참조하는 HandlerMethod 객체로 메서드 정보를 참조 할 수 있다.

postHandle()

postHandle() 메서드는 컨트롤러의 메서드가 비즈니스 로직을 실행 완료한 후 실행된다. 전달 받는 인자의 역할은 preHandle() 메소드와 같으며 추가로 ModelAndView 객체가 인자로 선언되어 있기 때문에 ModelAndView에 포함된 데이터를 참조할 수 있다.

afterCompletion()

afterCompletion() 메서드는 뷰가 실행 완료된 후 DispatcherServlet이 사용자에게 응답하기 직전에 실행되는 메서드로 ModelAndView 객체 대신 Exception 객체를 인자로 받기 때문에 이 에러 객체를 사용하여 예외 처리를 할 수 있다.

인터셉터(Interceptor)와 AOP의 비교

인터셉터와 AOP는 둘다 공통 기능을 분리하여 특정 클래스나 메소드를 호출할 때 부가 기능을 실행할 수 있지만 다음과 같은 이유로 컨트롤러의 호출 과정에서는 인터셉터를 사용하는 편이 낫다.

  1. 컨트롤러는 타입과 실행 메소드가 모두 제각각이라 포인트컷(적용할 메소드 선별)의 작성이 어렵다.
  2. 컨트롤러는 파라미터나 리턴 값이 일정하지 않다.

Filter와 Interceptor의 차이와 용도

Filter와 Interceptor의 차이

위 표를 보면서 차이점을 설명해 보면 먼저 필터의 경우 스프링 범위 밖에서 처리 되기 때문에 웹 컨테이너에 의해서 관리되고 인터셉터는 스프링 안에서 실행되므로 스프링 컨테이너에 의해서 관리된다.

 

두 번째는 필터는 Request/Response 객체 조작이 가능하지만 인터셉터는 불가능하다.

public class MyFilter implements Filter {
 
    @Override
    public void doFilter(ServletRequest request, 
                         ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {

        chain.doFilter(request, response);
    }
    
}

위 코드를 보면 필터는 다음 필터를 호출하기 위해 FilterChain의 doFilter() 메서드를 호출할 때 request와 response 객체를 넘겨주기 때문에 우리가 원하는 request와 response 객체를 넘겨줄 수 있다.

public class MyInterceptor implements HandlerInterceptor {
 
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) throws Exception {
    
        return true;
    }
    
}

하지만 인터셉터는 DispatcherServlet의 응답객체인 HandlerExecutionChain에 인터셉터가 등록되어 있고 순차적으로 실행되기 때문에 위 코드와 같이 request와 response를 담아서 넘겨줄 수 없다.

Filter와 Interceptor의 용도

Filter의 용도

  • 공통된 보안 및 인증/인가 관련 작업
  • 모든 요청에 대한 로깅 또는 감사
  • 이미지/데이터 압축 및 문자열 인코딩
  • Spring과 분리되어야 하는 기능

필터에서는 보통 스프링과는 무관하게 전역적으로 처리해야 하는 작업들을 처리할 수 있다. 또한 DispatcherServlet 앞 단에서 가장 먼저 사용자 요청을 받기 때문에 보안 검사를 수행할 수 있다.

 

Interceptor의 용도

  • 세부적인 보안 및 인증/인가 공통 작업
  • API 호출에 대한 로깅 또는 감사
  • Controller로 넘겨주는 정보(데이터)의 가공

인터셉터에서는 클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업들을 처리할 수 있는데 대표적으로 세부적으로 적용해야 하는 인증이나 인가와 같이 클라이언트 요청과 관련된 작업 등이 있다. 예를 들어 특정 그룹의 사용자는 어떤 기능을 사용하지 못하는 경우가 있는데, 이러한 작업들은 컨트롤러로 넘어가기 전에 검사해야 하므로 인터셉터가 처리하기에 적합하다.