Filter vs Interceptor vs AOP

한 줄 정의

Filter는 서블릿 컨테이너 수준에서 요청/응답을 가로채고, Interceptor는 Spring MVC의 DispatcherServlet 이후에 동작하며, AOP는 특정 빈의 메서드 실행 전후에 동작하는 횡단 관심사 처리 기법이다.

실무에서 왜 중요한가

  • 로깅, 인증, 인코딩 등 공통 처리를 어디에 구현할지 판단하지 못하면 부적절한 위치에 코드를 넣게 된다.
  • Spring Security의 Filter Chain을 이해하려면 Filter의 위치를 알아야 한다.

실행 흐름

HTTP 요청
    │
    ▼
┌───────────────────────────────────────────���─┐
│  Servlet Container (Tomcat)                 │
│  ┌───────────────────────────────────────┐  │
│  │  Filter Chain                         │  │
│  │  Filter 1 → Filter 2 → Filter 3      │  │
│  └───────────────┬───────────────────────┘  │
└──────────────────┼──────────────────────────┘
                   ▼
┌─────────────────────────────────────────────┐
│  Spring MVC (DispatcherServlet)             │
│  ┌───────────────────────────────────────┐  │
│  │  HandlerInterceptor                   │  │
│  │  preHandle → Controller → postHandle  │  │
│  └───────────────┬───────────────────────┘  │
│                  ▼                           │
│  ┌───────────────────────────────────────┐  │
│  │  AOP Proxy                            │  │
│  │  @Around → Service 메서드 → @Around   │  │
│  └───────────────────────────────────────┘  │
└─────────────────────────────────────────────┘

비교

구분FilterInterceptorAOP
소속Servlet ContainerSpring MVCSpring Bean
동작 위치DispatcherServlet 이전/이후Controller 이전/이후빈 메서드 실행 전후
설정 대상URL 패턴URL 패턴 + Handler포인트컷 (클래스, 메서드)
Spring 빈 접근제한적 (DelegatingFilterProxy 필요)가능가능
예외 처리직접 처리 (try-catch)Spring MVC 예외 처리 활용 가능Spring MVC 예외 처리 활용 가능
Request/Response 조작가능 (래핑)가능불가
적용 대상모든 요청 (정적 리소스 포함)Spring MVC 요청만지정한 빈의 메서드

각각의 역할과 예시

Filter

서블릿 스펙이므로 Spring에 의존하지 않는다. 요청/응답 자체를 조작할 수 있다.

@Component
public class EncodingFilter implements Filter {
 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response); // 다음 필터 또는 서블릿으로 전달
    }
}

적합한 용도:

  • 인코딩 설정
  • CORS 처리
  • 요청/응답 로깅 (body 래핑)
  • Spring Security 인증/인가 (FilterChain)
  • XSS 방어

Interceptor

Spring MVC에서 제공하며, Controller 호출 전후에 동작한다.

@Component
public class AuthInterceptor implements HandlerInterceptor {
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) {
        String token = request.getHeader("Authorization");
        if (!tokenService.isValid(token)) {
            response.setStatus(401);
            return false; // Controller 호출 안 함
        }
        return true;
    }
 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) {
        // Controller 실행 후, 뷰 렌더링 전
    }
 
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) {
        // 뷰 렌더링 후 (리소스 정리)
    }
}

적합한 용도:

  • 인증/인가 체크 (간단한 경우)
  • API 요청 로깅 (Controller 기준)
  • 요청별 공통 데이터 세팅
  • 실행 시간 측정 (Controller 단위)

AOP

Spring 빈의 메서드 수준에서 동작한다. URL이 아닌 클래스/메서드 단위로 적용.

@Aspect
@Component
public class ServiceLoggingAspect {
 
    @Around("execution(* com.example.service.*.*(..))")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long elapsed = System.currentTimeMillis() - start;
        log.info("{} executed in {}ms", joinPoint.getSignature().getName(), elapsed);
        return result;
    }
}

적합한 용도:

  • 트랜잭션 관리 (@Transactional)
  • Service/Repository 메서드 실행 시간 측정
  • 재시도 로직 (@Retryable)
  • 메서드 수준 권한 체크
  • 캐싱 (@Cacheable)

실무 선택 기준

요구사항선택이유
모든 요청의 인코딩/CORSFilterDispatcherServlet 전에 처리해야 함
요청/응답 body 로깅Filterbody를 래핑해서 읽어야 함
Spring Security 인증FilterSecurity Filter Chain이 Filter 레벨
특정 URL의 인증 체크InterceptorURL 패턴 + Spring 빈 접근 필요
Controller 실행 전 공통 검증InterceptorHandler 정보 접근 가능
Service 메서드 실행 시간AOP메서드 단위 적용
트랜잭션, 캐싱, 재시도AOP메서드 수준 횡단 관심사

자주 나는 실수

  • Filter에서 Spring 빈을 주입받으려고 @Autowired를 쓰는데 동작하지 않는다 (DelegatingFilterProxy 필요).
  • Interceptor에서 request body를 읽으면 Controller에서 다시 읽을 수 없다 (body는 1회성 스트림).
  • AOP를 URL 기반으로 적용하려고 한다 (AOP는 빈/메서드 기반).
  • 모든 공통 로직을 AOP로 해결하려고 해서 Filter/Interceptor가 더 적합한 경우를 놓친다.
  • Interceptor의 postHandle은 Controller 예외 시 호출되지 않는 것을 모른다 (afterCompletion은 호출됨).

핵심 요약

Filter는 서블릿 컨테이너 수준에서 모든 요청을 가로채고, Interceptor는 Spring MVC의 Controller 전후에 동작하며, AOP는 빈의 메서드 단위에서 동작합니다.

요청/응답 조작이 필요하면 Filter, URL + Handler 기준 처리는 Interceptor, 메서드 수준 횡단 관심사는 AOP를 사용합니다. Spring Security는 Filter 레벨에서 동작하고, @Transactional은 AOP로 동작한다는 것을 이해하면 전체 구조가 보입니다.

꼬리 질문

점검 퀴즈

아래 문항은 개념을 실제로 설명할 수 있는지 점검하기 위한 것이다. 선택지를 누르면 정답 여부와 이유가 표시된다.

객관식Spring Security가 주로 Filter 체인에서 동작하는 이유는?

OXInterceptor의 preHandle에서 false를 반환하면 이후 Handler 실행을 막을 수 있다.

객관식Filter에서 request body를 로깅할 때 주의할 점은?

관련 문서