
Spring Filter
우선 Spring Filter는 javax.servlet.Filter 인터페이스를 구현한 클래스 입니다.
HTTP 요청이 DispatcherServlet에 도달하기 전이나
응답이 사용자에게 반환되기 전에 동작하는 클래스 입니다.
쉽게 말해
웹 애플리케이션에서 모든 요청이나 응답이 지나가는 '중간 관문' 말 그대로
중간에서 무언가를 걸려주는 '필터' 의 역할을 합니다.
이 필터는 클라이언트가 보낸 요청이 본격적으로 처리되기 전이나
응답이 클라이언트에게 가기 전에 먼저 검사하거나 조작할 수 있는 것입니다.

Spring Filter는 위 그림과 같은 흐름으로 작동합니다.
예를 들어서 사용자가 /board 주소로 요청을 보냈다면
이 요청이 메서드를 호출하는 컨트롤러로 가게 되는데,
컨트롤러에 가기 전에 필터가 먼저 받아서
로그를 찍거나, 헤더에 토큰이 있는지 검사하는 등의 과정을 거치고
컨트롤러가 로직을 완료하고 응답을 보낼때에도
사용자에게 전달하기 전에 필터가 개입해서
응답에 해더를 추가하거나 로그를 찍고 데이터를 조작하는 등의
중간 과정을 거친 뒤 응답이 사용자에게 전달되게 됩니다.
즉 Spring Filter는 Spring MVC보다 먼저 작동하고 마지막에도 작동하는
보안 검색대와 같은 역할을 하게 됩니다.
그럼 이걸 왜씀?
우선 Spring Filter는 모든 요청과 응답을 관통하는 위치에 있습니다.
DispatcherServlet 보다 앞에 있기 때문에 애플리케이션
전체의 요청이나 응답 흐름에 대입할 수 있습니다.
이말이 무슨 말이냐 하면 컨트롤러나 서비스가 몰라도 되는
로그인 인증이나 로그 수집, 보안 검사 등의 공통 작업을
Spring Filter에서 처리할 수 있게 됩니다.
중복 코드를 방지하고 유지보수가 용이하기도 합니다.
요청마다 공통으로 해야하는 작업을 컨트롤러마다 넣는다면
코드가 GSM 복도보다 길어져서 유지보수하는 개발자가 갈려나갈수 있습니다.
이때 Spring Filter를 사용하면 중복되는걸 제거하고 관심사의 분리 등을 할수 있습니다.
예를 들어서 비행기를 탈때 안전을 위해 보안 검색을 하는데
500명의 승객이 모두 자리에 앉은 뒤에 보안 검색을 하게 되면
이미 보안 검색을 한 승객인지 모르고 한번 더 하거나 안하고 넘어갈수도 있습니다.
하지만 비행기에 타기전 한곳에서 보안 검색을 해서 중복을 방지하듯이
Spring Filter가 이와 같은 역할을 합니다.
보안 때문에 Spring Filter를 사용하기도 합니다.
필터는 요청이 컨트롤러에 도달하기 전에 작동하기 때문에
불필요하거나 위험한 요청은 컨트롤러까지 도달하지도 못하고
빠르게 거절할 수 있기에 성능에도 도움이 됩니다.
예를 들어 누군가 /admin/deleteAllUser 같은 위험한 URL을 호출하거나
JWT 토큰 없이 요청을 보내거나 수상한 IP에서 접근을 시도하는 등의
이상하고 위험한 요청을 보낼 때 필터는 컨트롤러에 도달하기 전에 작동하니까
문제 있으면 컨트롤러에 도달하기 전에 미리 차단해버리는 기능을 합니다.
그렇게 되면 요청이 Controller나 DB까지 갔다가 이거 좀 이상한데?
하고 거절하는 것보다 처음부터 걸러서 안 보내는게 빠르고 리소르를 아껴서
성능에도 도움을 주게 됩니다.
Spring Filter는 Spring 전용 기술이 아니라 Java 웹 애플리케이션의 표준 기술이기 때문에
Tomcat이나 Jetty, Undertow같은 다른 기술과도 연동이 잘 됩니다.
예를 들어서 내가 만든 웹 서비스가 Tomcat 서버로 돌아가고 있는데
회사에서 보안을 더 강화하라는 지침이 내려온다면
Filter는 Spring이 아니라 Tomcat 서버 수준에서 등록될 수 있기 때문에
Spring 안쪽 코드를 뜯지 않아도 외부 시스템과의 연동이 잘 됩니다.
다른 컴포넌트들과 비교되는 위치기에 Filter를 사용하기도 합니다.
예를 들어 AOP는 메서드 실행 전후에 Bean을 대상으로 동작하고
Intercepter는 Controller 전후에 Spring Handler를 대상으로 동작하게 됩니다.
하지만 Filter는 DispatcherServlet 이전과 이후에 모든 HTTP 요청과 응답을 대상으로
동작되기 때문에 시스템의 모든 부분을 통제할 때 Filter가 꼭 필요합니다.
장단점
우선 장점부터 하겠습니다.
- 공통 기능을 한곳에 모아 관리할 수 있습니다.
- 서블릿 요청 전반에 대해 작동하기 때문에 Controller에 의존하지 않습니다.
- 필터 체인으로 순서 제어가 가능합니다
다음은 단점입니다.
- Spring의 DI나 AOP와의 결합성이 낮습니다
- Request나 Response를 다룰 때 캐스팅과, 스트림 재사용 등의 문제가 있어서 불편합니다.
- 복잡한 비즈니스 로직에는 부적합합니다.
공항 보안 검색대에서 폭탄을 발견할 수는 있지만
해체하는건 폭탄처리반이 하듯이
이처럼 Filter는 단순하고 공통적인 작업에는 용이하지만
복잡한 로직을 처리하는 작업에는 부적합 합니다.
주요 기능
그렇다면 공통적이고 단순한 작업에 적합한 Filter는 보통 어떤 작업을 할 때 쓰일까요?
첫번째로 요청 로깅 입니다.
클라이언트가 서버에 어떤 URL로, 누가, 언제 요청했는지 등의
로그를 남기는 작업입니다. 이는 디버깅할 때나 보안 사고가 발생했을 때
기록으로 추적할 수 있습니다.
두번째는 보안 처리 입니다
요청이 인증된 사용자에게서 온 것인지, 허용된 요청인지
JWT 토큰과 세션, IP 주소 등으로 판단합니다.
로그인이 안되어있는 사용자가 /mypage 요청을 보냈을 때 막거나
교내 웹서비스를 운영하는데 파키스탄 IP 주소로 관리자 페이지를 접근하려 할 때
거부할수 있습니다.
세번째는 인코딩 설정 입니다.
클라이언트가 보낸 요청이나 서버에서 보내는 응답의
문자 인코딩 방식을 설정합니다.
한글이 꺠지는 문제나, 외국어와 특수문자를 처리할 때 사용됩니다.
네번째는 요청 전처리 입니다.
Controller 실행 전에 공통된 검사나 수정을 미리 처리합니다.
특정 헤더가 꼭 포함되어야 할 때나
특정 경로의 요청만 허용할 때 필터를 사용합니다.
마지막은 응답 후처리 입니다.
Controller에서 응답을 만든 후에
모든 응답에 공통 헤더를 추가하거나 응답 본문에 로그를 남기는 등
응답을 가공하거나 추가 처리할 때 사용합니다.
사용법
그렇다면 이러한 필터를 어떻게 사용할까요?
대표적으로 두가지 방법이 있습니다.
우선 @Component 어노테이션으로 자동 등록하는 방법입니다.
제가 소개할 두 방법 중에는 더 쉬운 방법이라고 생각합니다.
특별한 설정이 필요 없거나 간단한 로깅, 인증 필터 등에 자주 사용되는 방식입니다.
@Component
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
System.out.println("요청 URI: " + req.getRequestURI());
chain.doFilter(request, response);
}
}
위 코드는 예시 코드입니다.
@Component를 붙이면 Spring이 자동으로 등록해주게 됩니다.
모든 요청에 대해서 자동으로 필터가 실행되게 되고
순서를 조절하거나 URL 패턴을 지정할 수는 없습니다.
다음 방법은 FilterRegistrationBean을 이용해서 수동으로 등록하는 방법입니다.
필터 실행 순서를 지정하거나 특정 URL에 필터를 적용, 여러 필터를 사용하는 등의
보다 복잡한 상황에서 사용합니다.
이 두 코드는 /secure/* 경로에만 필터를 적용하고, 순서를 지정하는 코드 입니다.
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String token = req.getHeader("Authorization");
if (token == null || token.isEmpty()) {
((HttpServletResponse) response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
chain.doFilter(request, response);
}
}
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<AuthFilter> authFilter() {
FilterRegistrationBean<AuthFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new AuthFilter());
registration.addUrlPatterns("/secure/*");
registration.setOrder(1);
return registration;
}
}
첫번째 코드에서 필터를 통과하면 다음으로 넘어가게 하고
두번째 코드에서는 넘어온 요청을 특정 URL 패턴에만 적용하거나
순서를 지정하게 됩니다.
마무리
Spring Filter는 클라이언트의 요청과 서버의 응답 사이에서
가로채서 전처리·후처리를 수행할 수 있는 컴포넌트입니다.
보안 검증, 로깅, 인코딩 설정 등 요청 전반에 대한 제어가 가능하며
DispatcherServlet 앞단에서 동작하기 때문에
모든 요청에 대한 공통 로직을 구현할 때 유용하게 사용됩니다.
'Spring' 카테고리의 다른 글
| [Spring] Servlet과 DispatacherServlet (2) | 2025.08.01 |
|---|---|
| [Spring] PSA란? (0) | 2025.07.22 |
| [Spring] IoC란? (0) | 2025.07.17 |
| [Spring] DI란? (0) | 2025.07.16 |
| [Spring] 어노테이션과 import는 무엇일까? (1) | 2025.06.09 |