백엔드 면접 용어 사전
Spring·JPAInterceptor

Filter vs Interceptor

Filter는 서블릿 컨테이너 단계, Interceptor는 스프링 MVC 단계에서 요청을 가로챈다.

둘 다 요청을 가로채는 장치지만 동작하는 계층이 다르다.

위치

클라이언트
   ↓
[서블릿 컨테이너 (톰캣)]
   ↓
★ Filter                    ← 서블릿 스펙. 스프링 밖
   ↓
[DispatcherServlet]
   ↓
★ Interceptor               ← 스프링 MVC. 컨텍스트 안
   ↓
[HandlerAdapter]
   ↓
★ AOP (@Around)             ← 프록시. 메서드 호출 단위
   ↓
[Controller]

바깥에서 안쪽 순으로 Filter → Interceptor → AOP다.

비교

FilterInterceptor
스펙서블릿(J2EE)스프링 MVC
관리 주체서블릿 컨테이너스프링 컨텍스트
스프링 빈 사용가능하지만 설정 필요자연스럽게 가능
요청/응답 교체가능(chain.doFilter(new Wrapper(req), res))불가
핸들러 정보모른다안다(HandlerMethod → 어떤 컨트롤러인지)
예외 처리@ControllerAdvice못 잡는다잡을 수 있다
적용 범위모든 요청(정적 리소스 포함)스프링이 처리하는 요청

Filter를 쓰는 경우

@Component
public class LoggingFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
        var wrapped = new ContentCachingRequestWrapper((HttpServletRequest) req);
        chain.doFilter(wrapped, res);     // 요청 객체를 교체해서 전달
    }
}
용도이유
인코딩 설정스프링이 읽기 전에 해야 한다
요청/응답 본문 로깅스트림은 한 번만 읽을 수 있어 래핑이 필요
XSS 필터링파라미터를 감싸서 치환
스프링 시큐리티실제로 필터 체인으로 구현되어 있다
CORS, 압축전역적·저수준 처리

요청 본문 로깅은 Filter로만 제대로 할 수 있다 — 인터셉터 시점에는 이미 컨트롤러가 스트림을 읽을 예정이라, 여기서 읽으면 컨트롤러가 못 읽는다.

Interceptor를 쓰는 경우

public class AuthInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res,
                             Object handler) {
        if (handler instanceof HandlerMethod hm) {
            var annotation = hm.getMethodAnnotation(LoginRequired.class);
            if (annotation != null && !isLoggedIn(req)) {
                res.setStatus(401);
                return false;                 // false 면 컨트롤러로 안 간다
            }
        }
        return true;
    }
}
용도이유
인증·인가 확인어떤 컨트롤러인지 알아 어노테이션 기반 판단 가능
로그인 사용자 정보 세팅스프링 빈을 자유롭게 쓸 수 있다
API 호출 시간 측정핸들러 단위
공통 모델 데이터 추가postHandle에서 ModelAndView 조작

세 메서드

preHandle()   — 컨트롤러 실행 전. false 반환 시 중단
postHandle()  — 컨트롤러 실행 후, 뷰 렌더링 전  (@RestController 에서는 의미 적음)
afterCompletion() — 뷰까지 끝난 후. 예외가 있어도 항상 실행 → 자원 정리에 적합

@ResponseBody를 쓰면 postHandle 시점에는 이미 응답이 나간 뒤라 응답을 바꿀 수 없다. REST API에서는 preHandleafterCompletion만 쓴다.

어떻게 고를까 — 판단 기준

  • 요청/응답 객체를 바꿔야 하나? — → Filter
  • 스프링이 처리하지 않는 요청도 포함해야? — → Filter
  • 어떤 컨트롤러인지 알아야 하나? — → Interceptor
  • 스프링 예외 처리에 태워야 하나? — → Interceptor
  • 특정 메서드 호출만 감싸고 싶나? — → AOP

예외 처리 차이가 실무에서 중요하다 — Filter에서 던진 예외는 @ControllerAdvice가 못 잡아 톰캣의 기본 오류 페이지가 나간다. 일관된 JSON 오류 응답을 주려면 Filter 안에서 직접 응답을 써야 한다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — Spring·JPA — IoC/DI·AOP·영속성 컨텍스트·N+1