스프링 인터셉터도 서블릿 필터와 같이 웹과 관련된 공통 관심사를 효과적으로 해결할 수 있는 기술이다.
서블릿 필터가 서블릿이 제공하는 기술이라면, 스프링 인터셉터는 스프링 MVC가 제공하는 기술이다. 둘다 웹과 관련된 공통 관심사를 처리하지만, 적용되는 순서와 범위, 그리고 사용방법이 다르다.
스프링 인터셉터의 흐름은 아래와 같다.
스프링 인터셉터는 DispatcherServlet과 컨트롤러 사이에서 컨트롤러 호출 직전에 호출된다.
어찌보면 당연하다. 스프링 MVC의 시작점이 DispatcherServlet이고, 스프링 인터셉터는 스프링 MVC가 제공하는 기능이기 때문에 결국 DispatcherServlet 이후에 등장하는게 맞다.
스프링 인터셉터도 서블릿 필터처럼 URL 패턴을 적용해서 WAS로 들어오는 특정 URL로의 요청중 원하는 요청만 골라서 공통 관심사 처리를 수행할 수 있다. 다만, 스프링 인터셉터의 URL 패턴은 서블릿 필터의 URL 패턴과 다르고, 매우 정밀하게 설정할 수 있다.
스프링 인터셉터도 아래와 같은 제한을 둘 수 있다. (편의상 흐름을 살짝 생략하겠다)
인터셉터도 적절하지 않은 요청이라고 판단하면, 컨트롤러를 호출하지 않고 거기에서 끝낼 수 있다.
필터와 동일하게, 체인으로 구성되어 있으므로 중간에 인터셉터를 자유롭게 추가할 수 있다.
지금까지 내용을 보면 서블릿 필터와 호출되는 순서만 다르고, 제공하는 기능을 비슷해보인다.
스프링 인터셉터가 서블릿 필터와 다른 점은 스프링 MVC에서 제공하는 기능이기 때문에 스프링을 이용하는 개발자에게 서블릿 필터보다 편리하고, 더 정교하고 다양한 기능을 지원한다는 것이다.
스프링 MVC가 제공하는 스프링 인터셉터 인터페이스를 보자.
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 {
}
}
서블릿 필터 인터페이스에서는 필터의 역할을 하는 실질적인 함수가 doFilter() 하나였다면, 인터셉터는 호출 전(preHandle), 호출 후(postHandle), 요청 완료 이후(afterCompletion) 와 같이 단계적으로 세분화 되어 있다. 또, 인터셉터는 어떤 컨트롤러(함수에서는 Handler로 받고있음)가 호출되는지 호출정보도 받을 수 있고, 어떤 ModelAndView가 반환되는지 응답정보도 받을 수 있다.
스프링 인터셉터 호출은 위의 그림과 같다.
정상적인 흐름일 경우,
만약에 Handler(Controller)에서 예외가 발생하면 어떻게 될까?
Controllerd에서 예외가 발생하는 비정상적인 흐름일 경우,
주의.
HandlerInterceptor를 구현한 스프링 인터셉터는 스프링에 의해서 싱글톤으로 관리되기 때문에, 인터셉터 내부에서 공유될 수 있는 멤버변수를 사용할 수 없다.
참고. 스프링 부트에서는 인터셉터를 손쉽게 등록하는 방법을 제공한다. @Configuration을 이용한 설정 파일에서 WebMvcConfigurer 인터페이스를 implements하여 addInterceptor() 함수를 오버라이딩 하면된다. 자세한 것은 필요할 때 찾아볼 것.
서블릿 필터와 비교해보면 상대적으로 스프링 인터셉터가 제공하는 기능이 더 편리하고, 정밀하다.
서블릿 필터와 스프링 인터셉터 둘다 웹과 관련된 공통 관심사를 해결하기 위한 기술이다. 상황에 맞게 둘 중 하나를 골라서 사용하면 된다.