1. 개요
보통 횡단 관심사(로깅, 트랜잭션, 인증/인가 등)를 분리하기 위해 Spring AOP를 많이 사용한다. Spring AOP 방식 외에도 관심사를 분리하기 위해 Filter 또는 Interceptor를 사용하기도 한다.
Filter와 Interceptor가 무엇인지 알아보고, 어떤 차이가 있는지 살펴보자.
2. 요청 처리 구조
필터와 Interceptor를 알아보기 전에 일반적인 Spring Boot 서버는 클라이언트 요청을 어떻게 처리하는지 간략하게 짚고 넘어가자.
클라이언트가 요청을 보내면 어떻게 처리될까?
클라이언트가 브라우저에서 요청을 보내면, 가장 뭔저 톰캣(WAS)이 이를 받는다. 톰캣은 웹 서버이자 서블릿 컨테이너로서 요청을 적절한 서블릿을 찾아 전달한다. 이때 Spring 컨테이너에 의해 등록된 서블릿이 DispatcherServlet이며, 톰캣은 해당 서블릿에 요청을 전달한다. DispatcherServlet은 프런트 컨트롤러 역할을 하면 HandlerMapping을 통해 적절한 Controller를 찾는다.
요청 흐름 구조

2. Filter
필터는 서블릿 컨테이너 레벨에서 동작하며, 요청이 DispatcherServlet에 도달하기 전이나 응답이 나가는 시점에 실행된다.
즉, 톰캣이 요청을 받은 뒤 DispatcherServlet에 전달하기 전에 URL이 패턴이 일치하면 필터를 거치게 된다.
또한, Filter는 Spring 컨테이너에 의해 관리되지 않는다.
그럼에도, Spring 빈과 연계가 가능한데, DelatingFilterProxy가 등장하고 가능해졌다.
요청 흐름 구조

Filter의 메서드
- Filter는 인터페이스이며 Spring Security에 사용하는 많은 필터들은 기본적으로 Filter 인터페이스를 구현하여 사용하고 있다.
- 필요하다면, Filter를 구현하여 등록할 수 있다.
public interface Filter {}
init()
- 필터 객체를 초기화하고 서비스에 추가하기 위해 메서드
- 서블릿 컨테이너가 필터를 처음 생성할 때 1회 호출한다.
default void init(FilterConfig filterConfig) throws ServletException {}
doFilter()
- URL 패턴이 일치하는 요청이 DispatcherServlet에 전달되기 전에 실행되는 메서드이다.
- FilterChain 객체의 doFilter를 통해 다음 대상으로 요청을 전달한다.
- doFilter() 메서드에 요청 전/후로 필요한 과정을 작성해 처리하도록 한다.
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;
destory()
- 필터 객체를 제거하고 자원을 반환하기 위한 메서드이다.
- 서블릿 컨테이너가 필터를 종료할 때 한 번 호출되며, 이후에는 더 이상 doFilter()가 실행되지 않는다.
default void destroy() {}
3. Interceptor
인터셉트는 Spring에서 제공하는 기술로써, DispatcherServlet이 컨트롤러를 호출하기 전이나 응답이 나가는 시점에 실행된다.
즉, Spring 컨테이너 위에서 동작한다. Interceptor는 HandlerExecutionChain에 의해 관리되는데, 여기서 하나 이상의 Interceptor가 있다면 순처적으로 Interceptor를 거쳐 Controller를 실행한다.
요청 흐름 구조

Interceptor 메서드
- Interceptor는 Spring에서 제공하는 인터페이스로, 이를 구현해서 사용하면 된다.
public interface HandlerInterceptor {}
preHandle()
- 컨트롤러가 호출되기 전에 실행된다.
- 따라서, 인증, 권한 검증, 로깅 등 컨트롤러 이전에 처리해야 하는 작업을 추가하면 된다.
- 메서드의 handler 파라미터는 HandlerMethod 타입으로, 요청을 처리할 컨트롤러 메서드 정보를 담고있다.
- 반환값이 boolean 형식이며 true이면 다음 단계로 진행되고, false이면 작업이 중단되며 컨트롤러나 다음 interceptor가 실행되지 않는다.
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
postHandle()
- 컨트롤러 호출된 후(view 렌더링 전, 응답 전)에 실행된다.
- 컨트롤러 반환한 데이터를 가공하거나, View에 전달할 model 속성을 조작할 수 있다.
- 메서드의 ModelAndView 파라미터는 view와 model 정보를 포함하고 있으며, 템플릿 엔진 기반 view를 사용할 때 필요한 객체이다.
- 하위 계층에서 예외가 발생하면 호출되지 않는다.
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}
afterCompletion()
- 모든 작업이 완료된 후에 실행된다.
- 요청 처리 중에 사용한 리소스 반환할 때 사용하기 적합하다.
- 하위 계층에서 예외가 발생하더라도 반드시 호출된다.
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}
4. Filter vs Interceptor
Spring에서는 Filter와 Interceptor 모두 요청을 전·후 처리를 담당할 수 있다.
하지만, Filter와 Interceptor를 관리하는 컨테이너가 다르기 때문에 동작 방식과 활용 범위에서 차이가 있다.
Filter는 서블릿 컨테이너에서 관리되고, Interceptor는 스프링 컨테이너에서 관리된다.
Filter는 서블릿 컨테이너에서 관리되기 때문에 스프링에서 처리하는 기능들을 적용받을 수 없다.
그럼에도 Spring에서 Filter를 스프링 빈으로 등록하거나, 빈을 주입받는 경우가 있다. 이는 DelegatingFilterProxy가 등장하고부터 가능하게 되었다.
예외 핸들링
Spring에서 보통 RestControllerAdvice를 통해 예외를 처리한다.
interceptor는 스프링 컨테이너에서 동작하기 때문에 Interceptor에서 예외가 발생하면 RestControllerAdvice가 예외를 잡아 처리한다.
@RestControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler
public ResponseEntity<?> handleException(Exception e) {
// 예외 처리
}
}
반면, Filter는 서블릿 컨테이널 레벨에서 동작하기 때문에 Spring MVC 위에서 동작하는 RestControllerAdvice는 예외를 잡을 수가 없다. 필터에서 발생한 예외는 필터 내부에서 직접 처리해야 500 에러를 방지할 수 있다.
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
// 필터 로직
chain.doFilter(request, response);
} catch (Exception e) {
// 예외 처리 추가 필요
}
}
Request / Response 조작 여부
Filter와 Interceptor 모두 Request와 Response 내부 상태(헤더, 속성)를 변경할 수 있다.
하지만, 객체 자체를 교체할 수 있는지 여부에 차이가 있다.
Filter는 내부 상태 변경뿐 아니라 doFilter() 메서드를 통해 request / response 객체를 전달하여 다른 객체로 바꿔칠 수 있다.
반면, Interceptor는 메서드 처리 방식으로 인해 Interceptor는 다른 객체로 바꿔칠 수 없다.
// Filter
public class CustomFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// Request / Response를 다른 객체로 교체 가능
chain.doFilter(new CustomRequest(), new CustomeResponse());
}
}
// Interceptor
public class CustomInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
}
Filter, Interceptor 용도
Filter는 클라이언트의 정적 리소스 요청을 포함한 모든 요청을 거친다.
반면, Interceptor는 Spring MVC 레벨에서 동작하며 Controller에 매핑되는 요청에만 거친다.
예를 들어, Spring Security를 사용하여 login / logout과 같은 작업을 필터(서블릿) 레벨에서 처리한다면, login / logout 요청에 대해서는 interceptor가 호출되지 않는다. 이러한 특징을 이해하면 상황에 따라 interceptor, filter 적절히 선택하여 사용할 수 있다.
Filter의 용도
- 모든 요청에 대해 공통된 작업을 수행해야 하는 경우
- 공통된 보안 및 인증 인가 관련 작업
- 모든 요청에 대한 로깅
Interceptor의 용도
- Controller 요청에 대한 공통된 작업을 수행해야 하는 경우
- 세부적인 보안 및 인증/인가 공통 작업
- API 호출에 대한 로깅 또는 감사
5. 정리
| Filter | Interceptor | |
| 관리 주체 | 서블릿 컨테이너 | 스프링 컨테이너 |
| 실행 시점 | DispatcherServlet 전 | DispatcherServlet 이후 |
| 예외 처리 | 내부 처리 필요 | RestControllerAdvice 가능 |
| request / response 객체 교체 여부 | 가능 | 불가능 |
| 주요 활용 | 모든 요청에 대한 공통된 작업을 수행 | Controller 요청에 대한 공통된 작업을 수행 |
참고자료
https://gowoonsori.com/blog/spring/architecture
https://sigridjin.medium.com/servletcontainer%EC%99%80-springcontainer%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%8B%A4%EB%A5%B8%EA%B0%80-626d27a80fe5
https://mangkyu.tistory.com/173
'Programming > Spring' 카테고리의 다른 글
| [JPA] JPA Soft Delete 지원하는 여러 방식들에 대한 고민(@SoftDelete, @SqlDelete, @SQLRestriction) (0) | 2026.01.04 |
|---|---|
| [Spring] Spring MVC에서 Pageable 파라미터가 동작하는 방식 (1) | 2025.09.16 |
| [Spring Security] SecurityFilterChain 동작 분석 - Logout 요청 시 AuthenticationEntryPoint 미호출 문제 (3) | 2025.08.13 |
| [Spring 테스트] Mockito ArguementCaptor란? (1) | 2025.08.10 |
| [Spring 테스트] 테스트 간 데이터 충돌 문제 해결(@Sql 이해) (0) | 2025.07.11 |