스프링 | 스프링 부트

[ Spring ] Filter / FilterChain 개념, 사용법

Adose 2025. 2. 26. 17:45

📘 Filter

✅ Filter의 역할

  • Filter요청을 가로채서 처리하는 개별 필터이며, 서블릿에 도착하기 전 여러가지 문(필터)이다.
  • 필터가 없다면 요청이 바로 서블릿에게 도착하겠지만, 필터가 있다면 필터에 걸쳐 → 걸쳐 → 걸쳐서 서블릿에 도착한다.

 

✅ Filter의 동작 흐름

  1. 클라이언트 요청이 서블릿에 도착하기 전에 요청을 가로채서 필터처리(전처리)
  2. 서블릿이 응답을 반환할때 응답을 가로채서 후처리 해준다.

 

✅ Filter Chain과의 관계

  • 여러개의 필터가 존재할 경우 체인 형태(Filter Chain)로 연결되어 실행된다.
  • Filter가 요청을 가로채서 필터링한 후, FilterChain을 매개변수로 받아서 FilterChain.doFilter(request, response)를 실행하면 다음 필터 또는 서블릿으로 전달된다.

 

✅ Filter의 메서드

 

1️⃣ init()

public class CaramiFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
        log.info("CaramiFilter init()");
    }
  • 필터/서블릿 최초 실행 시 1회 실행된다.
  • 초기화 시켜주는 역할이라고 생각하면 된다. ( = 초기설정 )

 

2️⃣ doFilter(request, response, FilterChain)

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        log.info("CaramiFilter dofilter() 실행 전 ");
        //다음 필터 서블릿 호출
        chain.doFilter(request,response);
        log.info("CaramiFilter doFilter() 실행 후 ");

    }
  • 클라이언트 요청이 올때마다 실행된다.
  • chain.doFilter(request,response);
    • 위 코드를 사용해서 다음 필터 또는 서블릿으로 전달해야 한다.
  • log.info("CaramiFilter doFilter() 실행 후 ");
    • 요청이 필터를 치나고 서블릿에 도달하고, 서블릿이 응답을 보내면 그 응답이 필터로 돌아오면서 실행되는 것이다.
    • 이를 통해 응답이 돌아오면, 현재 필터에서 후처리 작업을 할 수 있다는 것을 알 수 있다 (Ex. 응답 수정, 로그 찍기 등 )

 

3️⃣ destory()

    @Override
    public void destroy() {
        log.info("CaramiFilter destory()");
        Filter.super.destroy();
    }
  • 서버 종료 또는 필터/서블릿 제거 시 실행된다.

 

📘 FilterChain

 

✅ FilterChain의 역할

  • FilterChain은 여러 개의 필터를 연결해서 실행하는 역할을 한다.
  • 필터에서 다음 필터 또는 최종 서블릿으로 요청을 전달하는 역할을 한다.

 

✅ Filter Chain의 생성 ?

  • 클라이언트가 애플리케이션에 요청을 보내면, 컨테이너는 요청 URL 경로에 따라 HttpServletRequest를 처리해야하는 필터 인스턴스와 서블릿이 포함된 FilterChain을 생성한다.
  • HttpServletRequest와 HttpServletResponse는 최대 하나의 서블릿만 처리할 수 있지만 여러 필터를 사용할 수 있다.

 

✅ FilterChain의 메서드

  • FilterChain은 하나의 메서드 doFilter만 가지고 있다.

1️⃣ doFilter(request, response)

public void doFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {
    if (currentFilterIndex < filters.length) {
        // 현재 필터 실행 후, 다음 필터로 이동
        filters[currentFilterIndex++].doFilter(request, response, this);
    } else {
        // 마지막 필터 이후에는 서블릿 실행
        servlet.service(request, response);
    }
}

 

📘 Filter와 FilterChain의 동작흐름

  1. 요청이 들어오면 서블릿 컨테이너(=Tomcat)이 요청을 처리하기 전 빈으로 등록된 필터를 확인한다.
  2. 빈으로 등록된 필터들이 실행된다.
    • 각 필터는 doFilter()메서드를 구현하고 있으며, 필터 체인을 통해 다음 필로 요청을 전달한다.
    • 이때 FilterChain은 서블릿 컨테이너가 자동으로 관리하고, 연결하여 체인 형태로 구성한다.
  3. FilterChain의 역할을 현재 필터에서 다음 필터로 요청을 넘기는 것이고, 이 체인을 통해 모든 필터가 실행된 후에 최종적으로 서블릿이 실행된다.

 

📘 필터의 다양한 사용법

✅ 필터가 실행되는 순서를 정하고 싶다면 ? - order(숫자) 사용

@Slf4j
@Component
@Order(2)
public class CaramiFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        log.info("CaramiFilter dofilter() 실행 전 ");
        chain.doFilter(request,response);
        log.info("CaramiFilter doFilter() 실행 후 ");

    }
}

@Slf4j
@Component
@Order(1)
public class UserFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        log.info("UserFilter doFilter 실행 전");
        chain.doFilter(request,response);

        log.info("UserFilter doFilter 실행 후");
    }
}
  • order(숫자) 를 사용한다.
    • 숫자에 따라서 순서대로 적용 된다.

 

✅ 원하는 URL에만 필터를 적용하고 싶다면 ?

 

📌 필터를 특정 URL에만 적용하는 방법 - 1

@Slf4j
@Component
@Order(2)
@WebFilter(urlPatterns = "/test/*")a- > 모든 요청이 들어왔을때 해당 필터를 거칠것이다.
public class CaramiFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
        log.info("CaramiFilter init()");
    }
  • WebFilter를 사용하여 urlPattern에 원하는 url을 적으면 된다.
  • 하지만 이 방법은 Spring에서 제대로 동작하지 않아서 Config 파일을 만들어서 좀 더 상세하게 직접 Url 패턴을 지정해서 사용하는 방법이 선호된다고 한다.

 

📌 필터를 특정 URL에만 적용하는 방법 - 2 (config 사용)

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<CaramiFilter> caramiFilter(){
        FilterRegistrationBean<CaramiFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new CaramiFilter());
        registrationBean.addUrlPatterns("/test/*");
        registrationBean.setOrder(2);

        return registrationBean;
    }
  • spring Boot에서는 FilterRegistrationBean을 사용하여 필터를 특정 URL 패턴에만 사용될 수 있게 적용할 수 있다.
  • registrationBean.addUrlPatterns("/test/*");
    • 위의 코드를 사용하면, 특정 url 패턴에서만 코드가 작동된다.
    • 위 코드는 /test로 시작되는 모든 url에 필터가 적용된다는 뜻이다.

 

🤨 만약 필터에 특정 url을 지정해주지 않는다면 ?

모든 url에 해당 필터가 적용된다 !