Exception Handling에 대해 공부하던 중, Spring에서 Controller까지 요청/응답이 이동하는 과정에 대해 고민하게 됐다. 그 과정에서 Filter와 Interceptor에 대한 지식이 부족함을 깨닫고 이를 보완하고자 포스팅을 작성한다. 🌱
Spring에서 Filter와 Interceptor를 사용하는 이유
개발을 주로 하다보면, 공통적으로(중복적으로) 처리해야되는 업무들이 많다.
공통 업무와 관련된 코드들이 페이지마다 존재한다면,
- 중복 코드가 많아지고
- 서버에 부하를 줄 수도 있고
- 소스 관리 역시 어려워진다.
Spring은 이런 사태를 방지하고자 공통적으로 여러 작업을 처리함으로써 중복된 코드들을 제거할 수 있는 여러 기능을 지원한다. Filter와 Interceptor는 그 기능들 중 하나이며, 구체적으로 알아보자.
Filter
J2EE 표준 스펙 기능으로 Dispatcher Servlet에 요청이 전달되기 전/후에 url 패턴에 맞는 모든 요청에 대한 부가작업을 처리할 수 있는 기능을 제공
- Spring Container가 아닌 Tomcat과 같은 Web Container(Servlet Container)에 의해 관리가 되는 것
- Spring Bean으로도 등록은 가능
- Dispatcher Servelt 전/후로 처리
Dispatcher Servlet에 대한 자세한 포스팅 : https://for-if.tistory.com/53

Filter Method 종류
Filter를 사용하려면, javax.servlet의 Filter 인터페이스를 구현(implements) 해야한다.
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() {}
}
init 메소드
Filter 객체를 초기화하고 서비스에 추가하는 메서드
Web Container가 init 메소드를 1회 호출하여 Filter를 초기화시, 이후의 요청들은 doFilter을 통해 처리된다.
doFilter 메소드
Url-Pattern에 맞는 모든 HTTP 요청이 Dispatcher Servlet으로 전달되기 전에 Web Container에 의해 실행되는 메서드
- doFIlter의 파라미터 ⇒ FilterChain
ex) chain.doFilter() 전/후에 우리가 필요한 처리과정을 넣어줌으로써 원하는 처리를 진행
- doFIlter의 파라미터 ⇒ FilterChain
destroy 메소드
Filter 객체를 서비스에서 제거하고, 사용하는 자원을 반환하기 위한 메서드
Web Container가 destory 메소드를 1회 호출하며, doFilter에 의해 처리되지 않는다.
Interceptor
Spring이 제공하는 기술로, Dispatcher Servlet이 Controller를 호출하기 전/후에 요청과 응답을 참조하거나, 가공할 수 있는 기능을 제공
- Web Container가 아닌 Spring Context에서 동작
- Dispatcher Servlet은 Handler Mapping(2번과정)을 통해 적절한 Controller를 찾도록 요청 ⇒ HandlerExecutionChain을 돌려줌
- HandlerExecutionChain에 1개 이상의 Interceptor가 등록되어 잇다면, 순차적으로 Interceptor들을 거쳐 Controller가 실행됨
- 만약 없다면 ? 바로 Controller 실행
Dispatcher Servlet에 대한 자세한 포스팅 : https://for-if.tistory.com/53

Interceptor Method 종류
Interceptor을 사용하기 위해서는 org.springframework.web.servlet의 HandlerInterceptor 인터페이스를 구현(implements)해야한다.
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 메소드
Controller가 호출되기 전에 실행
ex) Controller 이전에 처리해야 할 전처리 작업에 사용
ex) 요청정보를 가공 및 추가하는 경우에 사용
- Object handler : preHandle 메소드의 3번째 파라미터
Handler Mapping이 찾아준 Controller Bean에 매핑되는 HandlerMethod라는 객체
ex) @RequestMapping이 붙은 메소드의 정보를 추상화한 객체
- return값이 false라면 ? 작업을 중단하여 이후의 컨트롤러는 진행되지 않는다.
- Object handler : preHandle 메소드의 3번째 파라미터
postHandle 메소드
Controller가 호출된 후에 실행
ex) Controller 이후에 처리해야 할 후처리 작업에 사용
만약, Controller 자체에 에러가 나면 postHandle 호출 x
afterCompletion 메소드
모든 View에서 최종 결과를 생성하는 일을 포함해 모든 작업이 완료된 후에 실행
ex) 요청 처리 중에 사용한 리소스를 반환할 때 사용
postHandle과 달리, 예외가 발생해도 반드시 호출 o
Filter vs Interceptor
대상 | Filter | Interceptor |
관리되는 Container | Servlet Container | Spring Container |
Spring 예외 처리 여부 | X (Servlet 영역이므로) | O |
Request/Response 가능 여부 | O | X |
용도 | - 공통된 보안 및 인증/인가 관련 작업 - 모든 요청에 대한 로깅 - 이미지/데이터 압축 및 문자열 인코딩 - Spring과 분리되어야하는 기능 | - 세부적인 보안 및 인증/인가 공통 작업 - API 호출에 대한 로깅 - Controller로 넘겨주는 정보 가공 |
🔗 참고 url
https://dev-coco.tistory.com/173
https://chb2005.tistory.com/93
Uploaded by N2T