[Spring]Filter와 Interceptor
공통관심사
어플리케이션 전반에서 여러 로직에 공통적으로 관심이 있는 것들을 공통관심사라고 한다.
어느 웹서비스를 이용하기 위해서 로그인(회원 인증)이 되었는지 확인하는 것을 여러 기능에서 필요로 하는 것이 있다.
상품의 구매, 변경, 취소 이 3가지의 기능만 예로 들어도 3가지 기능 모두 인증이 되었는지 확인한다.
공통관심사에 해당하는 부분이 서비스 로직 시행 전 위치함으로써 필요한 기능을 수행하게 되는 것이다.
Filter와 Interceptor의 기반
이 때 사용할 수 있는 것이 Filter(servlet Filter)와 Interceptor이다.
Filter는 J2EE 표준스펙에서 제공하는 기술로써 가장 앞단에 존재하는 프론트 컨트롤러인 디스패처 서블릿의 전후에서 필요한 기능을 수행하게 한다. (J2EE는 Java 2 EnterPrise Edition)
InterCeptor는 스프링이 제공하는 Dispatcher Servlet이 Controller를 호출하기 전에 요청을 가로채서(InterCept) 필요한 기능을 수행한다.
Servlet Filter와 InterCeptor는 웹과 관련된 공통관심사를 처리하기에 용이하다.
웹 관련 공통관심사에는 보통 URL 혹은 Header의 정보들이 필요한 경우가 많은데 이를 처리하기 위한 HttpServletRequest를 Filter와 Intercoptor가 제공하기 때문이다.
아래 이미지에서는 Servlet Filter와 Interceptor가 어느 위치에서 공통관심사를 처리하는지를 잘 보여준다.
Filter의 메소드
사용자 Filter를 구현하기 위해서 javax.sevlet의 Filter 인터페이스를 구현해야한다. 이 인터페이스의 메소드는 다음 3가지가 있다.
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
보통 필터를 구현할 때 핵심이 되는 메소드이다. 필요한 혹은 원하는 기능을 구현한 후 FilterChain 파라미터를 통해 다음 대상으로 요청을 넘겨준다.
destroy
필터를 제거하고 자원을 반환하기 위한 메소드이다.
Filter의 적용
@configuration 애노테이션이 붙여진 클래스의 빈으로 등록한다.
@Bean
public FilterRegistrationBean loginCheckFilter() {
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new LoginCheckFilter());
filterRegistrationBean.setOrder(2);
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
Interceptor의 메소드
사용자 Interceptor를 구현하기 위해서 스프링의 HandlerInterceptor를 구현해야한다. 구현 메소드는 3가지가 있다.
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
Controller 호출 전 호출(더 정확히는 핸들러 어댑터 호출 전에 호출)
preHandle 의 리턴 값이 true이면 다음으로 진행하고, false이면 더 이상 진행하지 않는다.
false일 경우, 나머지 인터셉터와 핸들러 어댑터도 호출되지 않는다.
postHandle
Controller 호출 후에 호출
afterCompletion
뷰가 렌더링 된 이후에 호출
InterCeptor의 적용
interceptor도 filter와 마찬가지로 WebConfig로 등록을 해두어야한다.
WebMvcConfigurer 클래스를 상속받아 addInterceptors 메소드를 오버라이딩하여 적용시킨다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.order(1)
.addPathPatterns("/**")
.excludePathPatterns("/css/**", "/*.ico", "/error");
}
//...
}