공통 관심사란 여러 로직에서 공통으로 관심이 있는 것이다.
예를 들어, 상품 관리 컨트롤러에서 로그인 여부를 체크하는 로직을 하나하나 작성하면 되겠지만, 등록,수정,삭제,조회 등등 상품관리의 모든 컨트롤러 로직에 공통으로 로그인 여부를 확인해야한다.
이러한 공통 관심사는 스프링의 AOP로도 해결할 수 있지만, 웹과 관련한 공통 관심사는 지금부터 설명할 서블릿 필터 또는 스프링 인터셉터를 사용하는 것이 좋다.
필터는 서블릿이 지원하는 수문장
필터 흐름
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러
필터 제한
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러 //로그인 사용자
HTTP 요청 -> WAS -> 필터(적절하지 않은 요청이라 판단, 서블릿 호출X) //비 로그인 사용자
필터 체인
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() {}
}
1) init(): 필터 초기화 메서드, 서블릿 컨테이너가 생성될 때 호출된다.
2) doFilter(): 고객의 요청이 올 때 마다 해당 메서드가 호출된다. 필터의 로직을 구현하면 된다.
3) destroy(): 필터 종료 메서드, 서블릿 컨테이너가 종료될 때 호출된다.
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean logFilter() {
FilterRegistrationBean<Filter> filterRegistrationBean = new
FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new LogFilter());
filterRegistrationBean.setOrder(1);
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
1) FilterRegistrationBean을 사용한다.
2) setFilter(new LogFilter()) : 등록할 필터를 지정한다.
3) setOrder(1) : 필터는 체인으로 동작한다. 따라서 순서가 필요하다. 낮을 수록 먼저 동작한다.
4) addUrlPatterns("/*") : 필터를 적용할 URL 패턴을 지정한다. 한번에 여러 패턴을 지정할 수 있다.
스프링 인터셉터 흐름
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러
스프링 인터셉터 제한
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러 //로그인 사용자
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터(적절하지 않은 요청이라 판단, 컨트롤러 호출
X) // 비 로그인 사용자
스프링 인터셉터 체인
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 인터셉터1 -> 인터셉터2 -> 컨트롤러
스프링 인터셉터 인터페이스
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse
response,
Object handler) throws Exception {}
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 {}
}

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

예외가 발생시
1) preHandle : 컨트롤러 호출 전에 호출된다.
2) postHandle : 컨트롤러에서 예외가 발생하면 postHandle 은 호출되지 않는다.
3) afterCompletion : afterCompletion 은 항상 호출된다. 이 경우 예외를 파라미터 로 받아서 어떤 예외가 발생했는지 로그로 출력할 수 있다
| 차이점 | 필터 | 인터셉터 |
|---|---|---|
| 제공자 | 서블릿 | 스프링 MVC |
| 제공 함수 | doFilter() | preHandle(), postHandle(), afterCompletion() |