[Spring] Filter vs Interceptor

gyeol·2025년 10월 17일

스프링

목록 보기
49/50
post-thumbnail


Filter, Interceptor, AOP는 모두 요청을 처리하는 과정과 관련이 있다. Filter, Interceptor, AOP가 적용된 스프링프레임워크가 외부에서 요청이 왔을 때 처리하는 흐름은 아래처럼 요약할 수 있다.

HTTP 요청
 ↓
[Filter] — 서블릿 컨테이너 단계
 ↓
DispatcherServlet
 ↓
[Interceptor: preHandle]
 ↓
Controller
 ↓
[Interceptor: postHandle]
 ↓
ViewResolver → View Rendering
 ↓
[Interceptor: afterCompletion]
 ↓
HTTP 응답

필터 (Filter)

Filterjavax.servlet의 표준 기술로,DispatcherServlet에 요청이 전달되기 전/후에 url 패턴에 맞는 요청에 대해 부가 작업을 처리할 수 있는 기능을 제공한다.

DispatcherServlet?
클라이언트의 요청을 받아 적절한 컨트롤러로 전달하고 처리 결과를 다시 뷰로 전달하는 프론트 컨트롤러를 말한다.

스프링 컨테이너가 아닌 웹 컨테이너에 의해 관리되는 것이며, DispatfherServlet 전/후에 처리하는 것이다.

  • 공통된 보안 및 인증/인가 관련 작업
  • 이미지/데이터 압축 및 문자열 인코딩
  • Spring과 분리되어야 하는 기능
  • 모든 요청과 응답에 대한 로깅

예제

DispatcherServlet이 실행되기 전 요청을 가로채서 요청 인코딩을 적용하고 요청 시간과 Request ID에 대해 로그를 남기는 코드이다.

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.UUID;

public class RequestLoggingFilter implements Filter{
	@Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException{
        	request.setCharacterEncoding("UTF-8");
            HttpServletRequest http = (HttpServletRequest) request;
            
            String rid = UUID.randomUUID().toString();
        	long start = System.currentTimeMillis();
            try {
            // MDC 등에 넣어서 로그 상관관계 추적 가능
            http.setAttribute("RID", rid);
            chain.doFilter(request, response); // 다음으로
          } finally {
              long took = System.currentTimeMillis() - start;
              System.out.printf("[Filter] %s %s rid=%s took=%dms%n",
                      http.getMethod(), http.getRequestURI(), rid, took);
          }
	}
}

이후 스프링 부트에서 등록하면 된다.

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<RequestLoggingFilter> requestLoggingFilter() {
        FilterRegistrationBean<RequestLoggingFilter> reg = new FilterRegistrationBean<>();
        reg.setFilter(new RequestLoggingFilter());
        reg.addUrlPatterns("/*");
        reg.setOrder(1); // 낮을수록 먼저
        return reg;
    }
}

인터셉터 (Interceptor)

Interceptor는 Spring MVC 라이브러리 중 하나로 DispatcherServlet이 컨트롤러를 호출하기 전과 후에 요청 응답을 참조하거나 가공할 수 있는 기능을 제공한다. Interceptor는 스프링 컨테이너 내에서 동작하기에 필터를 거쳐 DispatcherServlet이 요청을 받은 이후에 동작하게 된다.

  • 세부적인 보안 및 인증/인가 작업
  • API 호출에 대한 로깅 또는 검증
  • Controller로 넘겨주는 정보 가공

예제

컨트롤러 실행 전 후에 로그를 찍고 응답 직전에 모델에 공통 데이터를 추가하는 인터셉터 코드이다.

import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public class HandlerLoggingInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
        if (handler instanceof HandlerMethod hm) {
            String ctrl = hm.getBeanType().getSimpleName();
            String method = hm.getMethod().getName();
            System.out.printf("[Interceptor:pre] %s#%s %s%n", ctrl, method, req.getRequestURI());
        }
        // false를 리턴하면 체인 중단 (컨트롤러 호출되지 않음)
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest req, HttpServletResponse res, Object handler,
                           @Nullable ModelAndView mav) {
        if (mav != null) {
            mav.addObject("globalNotice", "서비스 점검 02:00~03:00");
        }
        System.out.println("[Interceptor:post] view=" + (mav != null ? mav.getViewName() : "null"));
    }

    @Override
    public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) {
        if (ex != null) {
            System.out.println("[Interceptor:afterCompletion] exception=" + ex.getMessage());
        }
        System.out.println("[Interceptor:afterCompletion] done");
    }
}

이후에 Interceptor를 등록해주고 경로 패턴을 설정해준다.

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry reg) {
        reg.addInterceptor(new HandlerLoggingInterceptor())
           .addPathPatterns("/**")
           .excludePathPatterns(
               "/css/**", "/js/**", "/images/**", "/favicon.ico",
               "/actuator/**", "/health"
           );
        // 등록 순서가 호출 순서에 영향
    }
}

주요 차이점

구분Servlet FilterSpring Interceptor
소속Servlet 표준 기술 (javax.servlet)Spring MVC 구성 요소
동작 시점DispatcherServlet 이전/이후DispatcherServlet 이후
적용 범위모든 요청 (정적 리소스 포함)컨트롤러 요청에 한정
접근 가능 데이터Request, ResponseHandler, Model, View
등록 방법web.xml / FilterRegistrationBeanWebMvcConfigurer#addInterceptors
주로 사용인코딩, 로깅, CORS, 보안인증, 로깅, 모델 가공
profile
공부 기록 공간 '◡'

0개의 댓글