- 서블릿 필터와 필터 체인의 구조, 동작 방식
- 직접 Servlet Filter를 구현하며 동작 원리 이해하기
- FilterChain의 실행 순서, 순서 지정 방법
- Spring Boot 환경에서 Filter를 등록하고 적용하는법
- 필터의 전처리 / 후처리 개념을 통해 보안 및 로깅과 같은 활용 방안 익히기
Servlet Filter, Filter Chain
1. Filter 개념
Servlet Filter는 서블릿 기반 애플리케이션의 엔드포인트에 요청이 도달하기 전에 중간에서 요청을 가로채 특정 작업을 수행할 수 있는 Java 컴포넌트임

- 클라이언트가 서버로 요청을 보낼 때 가장 먼저 Filter를 거친다
- Filter에서 전처리 / 후처리 로직을 실행한 후 DispatcherServlet으로 요청이 전달된다
2. Filter Chain 개념
Filter Chain은 여러개의 Filter가 연결되어 체인을 이루는 구조를 의미한다
- 요청이 들어오면 체인 형태로 나열된 Filter를 순서대로 통과한다
- 모든 Filter 처리가 끝난 뒤 Servlet이 실행된다
3. Filter와 Filter Chain 특성
- 요청 URI path 기반 처리 : 서블릿 컨테이너는 요청 URI를 기반으로 어떤 Filter와 Servlet을 맵핑할지 결정한다
- 순서 지정 가능 : Filter는 체인 내에서 실행 순서를 지정할 수 있다
- Spring Boot 순서 지정 방법
- Filter에 @Order 애너테이션 추가 또는 Ordered 인터페이스 구현하기
- FilterRegistrationBean의 setOrder() 메서드 이용하기
Filter 인터페이스 구조
- 일단 Filter를 implements 하는 클래스를 생성 및 구현함
- Configuration에 등록하기
import jakarta.servlet.Filter; // jakarta.servlet.Filter임
public class FirstFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
init() : Filter 초기화 작업을 수행하는 메서드
doFilter() : 전처리 -> 다음 필터 호출 -> 후처리하는 메서드
destroy() : 자원 반납 처리를 하는 메서드
Filter 구현
* 서블릿 필터와 리액티브 필터는 서로 다르다
1. FirstFilter.java (import를 보면 servlet 기반인 것을 알 수 있음)
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.io.IOException;
public class FirstFilter implements Filter {
// Filter 초기화 작업을 하는 init 메서드
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
System.out.println("---- FirstFilter init ----");
}
// 필터 동작 로직을 담당하는 doFilter 메서드
// 전처리 -> 다음 필터 호출 -> 후처리
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("---- FirstFilter Filter start ----");
filterChain.doFilter(servletRequest, servletResponse); // 다음 필터로 요청을 전달한다
System.out.println("---- FirstFilter Filter end ----");
}
// 종료시 자원 해제를 하는 destroy 메서드
// 자원을 반납함
@Override
public void destroy() {
System.out.println("---- FirstFilter destroy ----");
Filter.super.destroy();
}
}
2. FilterConfiguration에 등록하기
import com.b1uffer.mysecurity.filter.FirstFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfiguration {
// 서블릿 기반 Filter라서 리액티브 기반(WebFlux)에서는 필터가 동작하지 않는다
@Bean
public FilterRegistrationBean<FirstFilter> firstFilterRegistration() {
FilterRegistrationBean<FirstFilter> firstFilterRegistration = new FilterRegistrationBean<>(new FirstFilter());
return firstFilterRegistration;
}
}
* 리액티브(WebFlux) 기반 필터
FirstWebFilter.java
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
public class FirstWebFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
System.out.println("---- WebFilter start ----");
Mono<Void> filterChain = chain.filter(exchange).doOnTerminate(() -> { // chain.doFilter가 아니라 filter임
System.out.println("---- WebFilter end ----");
});
return filterChain;
}
FilterConfiguration.java
import com.b1uffer.mysecurity.filter.webflux.FirstWebFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfiguration {
@Bean
public FirstWebFilter firstWebFilter() {
return new FirstWebFilter();
}
}
다중 Filter 구성
1. SecondFilter 클래스 생성 및 구현
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.io.IOException;
public class SecondFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
System.out.println("---- SecondFilter init ----");
}
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("---- SecondFilter start ----");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("---- SecondFilter end ----");
}
@Override
public void destroy() {
System.out.println("---- SecondFilter destroy ----");
Filter.super.destroy();
}
}
2. FilterConfiguration에 SecondFilter를 등록하고 순서 정해주기
import com.b1uffer.mysecurity.filter.FirstFilter;
import com.b1uffer.mysecurity.filter.SecondFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfiguration {
// 서블릿 기반 Filter라서 리액티브 기반(WebFlux)에서는 필터가 동작하지 않는다
@Bean
public FilterRegistrationBean<FirstFilter> firstFilterRegistration() {
FilterRegistrationBean<FirstFilter> firstFilterRegistration = new FilterRegistrationBean<>(new FirstFilter());
firstFilterRegistration.setOrder(1); // 얘를 먼저 실행하고
return firstFilterRegistration;
}
@Bean FilterRegistrationBean<SecondFilter> secondFilterRegistration() {
FilterRegistrationBean<SecondFilter> secondFilterRegistration = new FilterRegistrationBean<>(new SecondFilter());
secondFilterRegistration.setOrder(2); // 얘를 나중에 실행함
return secondFilterRegistration;
}
}
* 필터는 순서가 중요하다. setOrder()의 값이 낮을수록 먼저 실행된다.
Spring Security와 서블릿 필터의 관계
Spring Security는 서블릿 필터 기반으로 동작하는 보안 프레임워크다
- 요청이 들어오면 Spring Security는 여러개의 보안 관련 필터를 체인으로 연결하여 실행한다
- 인증(Authentication), 인가(Authorization), 보안 이벤트 처리 등 대부분의 기능이 필터 체인 안에서 이루어진다
- 따라서 Spring Security를 이해하려면, 서블릿 필터의 동작 원리를 먼저 이해하는게 매우매우매우매우 중요하다
* 필터는 서블릿 컨테이너 레벨에서 동작하기 때문에 컨트롤러(Controller)보다 먼저 실행된다
* 필터에서 예외처리를 잘못하면, 응답 전체가 깨질 수 있으므로 주의가 필요하다
* 로깅, 인증, 인가와 같은 보안 관련 기능은 필터에서 처리하는게 일반적이다
* Spring Security 역시 이러한 구조를 기반으로 설계되었으므로, 필터 개념을 이해하면 Security 동작 원리를 쉽게 이해할 수 있다
핵심
- Filter는 요청을 가로채서 전처리 / 후처리를 수행할 수 있다
- 여러개의 Filter를 FilterChain으로 묶어서 순차적으로 실행할 수 있다
- Spring Boot에서는 FilterRegistrationBean을 통해 Filter로 등록하고, setOrder()나 @Order 애너테이션으로 실행 순서를 지정한다
- Filter의 실행 순서는 나머지 Filter와 Servlet의 동작에 직접적인 영향을 주므로 반드시 신중하게 설계해야한다
'Spring Boot > Security' 카테고리의 다른 글
| 필터 아키텍처 : 필터 순서와 우선순위 (1) | 2026.04.21 |
|---|---|
| 필터 아키텍처 : 주요 보안 필터 (0) | 2026.03.31 |
| 필터 아키텍처 : Spring Security 필터 구조 (0) | 2026.03.30 |
| Security : 플랫폼별 Spring Security (0) | 2026.03.27 |
| Security : Spring Security (0) | 2026.03.26 |