자바 백엔드 입문 26편. 요청 전후처리의 두 도구 Filter와 HandlerInterceptor의 정확한 차이·동작 위치·언제 무엇을 쓰는가를 공항 입국 절차 비유로 풀어쓴 학습 노트.
이 글은 자바 백엔드 입문 시리즈 59편 중 26편이에요. 25편 DispatcherServlet 에서 짧게 만난 Filter와 HandlerInterceptor — "비슷한데 다른 둘" 의 정확한 차이를 풀어 가요.
Filter·Interceptor가 헷갈리는 이유
둘 다 "요청 전후처리" 역할이라 — 처음 보면 어느 걸 쓰면 좋을지 안 잡혀요. "Servlet Filter? Spring Interceptor? AOP? 셋 다 비슷한데?" 가 흔한 질문.
이 글에서는 공항 입국 절차 비유로 풀어요. Filter = "공항 정문 보안 검색대" (모든 사람), Interceptor = "입국 심사관" (Spring 영역 진입자만). 끝까지 따라오시면 셋 다 한 그림에 들어와요.
동작 위치 — 가장 결정적 차이
[HTTP 요청]
↓
[ Servlet Filter (1) ] ← Tomcat 단계, Spring 밖
↓
[ Servlet Filter (2) ]
↓
[ DispatcherServlet ] ← Spring 진입
↓
[ HandlerInterceptor (1) ] ← Spring 안
↓
[ HandlerInterceptor (2) ]
↓
[ Controller 메서드 ] ← AOP 어드바이스도 여기 적용
↓
[ HandlerInterceptor (postHandle) ]
↓
[ HandlerInterceptor (afterCompletion) ]
↓
[ Filter (응답 처리) ]
↓
[HTTP 응답]
Filter는 Servlet 표준 (Spring 이전부터 있는 자바 EE 표준), Interceptor는 Spring 전용. Filter가 더 바깥쪽, Interceptor가 더 안쪽.
Filter 구현 — Servlet 표준
@Component
@Slf4j
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
long start = System.currentTimeMillis();
log.info("→ {} {}", req.getMethod(), req.getRequestURI());
chain.doFilter(request, response); // 다음 Filter 또는 DispatcherServlet 호출
log.info("← {}ms", System.currentTimeMillis() - start);
}
}
@Component 박으면 Spring Boot가 자동 등록. 또는 FilterRegistrationBean 으로 명시.
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<LoggingFilter> loggingFilter(LoggingFilter filter) {
FilterRegistrationBean<LoggingFilter> registration = new FilterRegistrationBean<>(filter);
registration.addUrlPatterns("/api/*"); // 특정 경로만
registration.setOrder(1); // 실행 순서
return registration;
}
}
Interceptor 구현 — Spring 전용
@Component
@Slf4j
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
String token = req.getHeader("Authorization");
if (token == null) {
res.setStatus(401);
return false; // false 반환 시 컨트롤러 호출 차단
}
return true;
}
@Override
public void postHandle(HttpServletRequest req, HttpServletResponse res, Object handler, ModelAndView mav) {
// 컨트롤러 호출 후, 응답 전송 전
}
@Override
public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) {
// 응답 전송 후 (예외 발생 여부 포함)
}
}
등록은 WebMvcConfigurer.
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
private final AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/auth/**", "/api/public/**");
}
}
excludePathPatterns 로 특정 경로 제외 가능. 39편 CORS 처럼 "/api/** 에 적용 + 예외" 패턴.
Filter vs Interceptor 비교표
| 구분 | Filter | Interceptor |
|---|---|---|
| 표준 | Servlet (자바 EE) | Spring 전용 |
| 위치 | DispatcherServlet 바깥 | DispatcherServlet 안 |
| 경로 매핑 | `UrlPatterns` | `PathPatterns` + `excludePathPatterns` |
| 접근 가능 | `HttpServletRequest`·`Response` | 위 + `Handler`·`ModelAndView` |
| Spring Bean 주입 | `@Component` 가능 | 당연히 가능 |
| Body 가공 | 가능 (Wrapper 사용) | 어려움 |
| 예외 처리 | `@ControllerAdvice` 못 잡음 | `@ControllerAdvice` 가 잡음 |
언제 무엇을?
Filter 선택
- 요청·응답 본문(Body)을 가공 — 압축·암호화·로깅 (Spring 진입 전후)
- 모든 요청에 적용 (정적 자원 포함)
- Spring 외 요청도 처리 — Servlet API만 사용
- 인증·인가 일부 — Spring Security가 Filter 기반
Interceptor 선택
- Spring MVC 컨텍스트 필요 — Handler 정보·ModelAndView
- 컨트롤러 호출 차단·전후 가공
- HTTP API 요청만 처리 (정적 자원 제외)
@ControllerAdvice와 협업 — 예외 처리 통합
AOP 선택 (참고)
- 메서드 단위 처리 — 트랜잭션·캐싱·로깅
- HTTP 컨텍스트 무관
세 도구가 같이 박혀 있을 수도 있어요. 책임 분리.
자주 만나는 시나리오
1. 요청 로깅
Filter 추천 — 모든 요청 (정적 자원 포함) 처리, 응답 시간 측정.
2. 인증·인가
Filter (Spring Security) 또는 Interceptor — 회사 정책. Spring Security 박혔으면 자동 Filter 기반.
3. CORS
Filter (CorsFilter) — Preflight OPTIONS 요청도 잡으려면 Filter가 안전.
4. 요청 ID 부여 (Trace ID)
Filter — 모든 요청에 적용 + MDC에 박아 로그 추적.
5. 컨트롤러별 권한 검증
Interceptor — Handler 정보로 어느 컨트롤러인지 알 수 있어 세밀한 분기.
6. 응답 본문 압축·캐싱
Filter — Body 가공 권한 있음.
Body 가공 또는 정적 자원 포함 → Filter. Spring MVC 정보 필요·컨트롤러 분기 → Interceptor. 메서드 단위 처리 → AOP. 셋이 협업 패턴이 회사 시스템 표준.
한 줄 정리 — Filter = Servlet 표준, DispatcherServlet 바깥. Interceptor = Spring 전용, 안쪽. Body 가공·정적 포함 = Filter, MVC 정보 필요 = Interceptor.
시험 직전 한 번 더 — Filter·Interceptor 입문자가 매번 헷갈리는 것
- Filter = Servlet 표준 (자바 EE). DispatcherServlet 바깥
- HandlerInterceptor = Spring 전용. DispatcherServlet 안
- 실행 순서 = Filter → DispatcherServlet → Interceptor → 컨트롤러
@ControllerAdvice는 Interceptor 예외만 잡음 (Filter 예외 X)- Filter 인터페이스 =
doFilter(req, res, chain) chain.doFilter()안 호출 = 진행 중단- Interceptor 메서드 3개 =
preHandle/postHandle/afterCompletion preHandle에서false반환 = 컨트롤러 호출 차단- Filter 등록 =
@Component자동 또는FilterRegistrationBean - Interceptor 등록 =
WebMvcConfigurer.addInterceptors addPathPatterns+excludePathPatterns조합- Filter는 응답 Body 가공 가능 (Wrapper)
- Interceptor는 Body 가공 어려움
- 정적 자원(HTML·CSS·JS·이미지) = Filter는 처리, Interceptor는 거의 X
- Spring Security 박힌 회사 = 인증·인가가 Filter 기반
- 요청 ID·Trace ID 부여 = Filter 표준
- 컨트롤러별 권한 검증 = Interceptor 적합 (
HandlerMethod활용) - 셋이 협업 가능 = Filter (로깅·CORS) + Interceptor (인증) + AOP (트랜잭션)
- 둘 다 Spring Bean으로 다른 의존성 주입 가능
- 실행 순서 제어 =
@Order또는 등록 순서
시리즈 다른 편 (앞뒤 글 모음)
이전 글:
- 21편 — Bean 생명주기 PostConstruct PreDestroy
- 22편 — SpEL 표현식 언어
- 23편 — AOP 횡단 관심사가 뭔가
- 24편 — @Aspect로 첫 AOP 박기
- 25편 — DispatcherServlet 요청 처리 흐름
다음 글: