GenericFilterBean vs OncePerRequestFilter
📌 Overview
Spring Security와 JWT를 이용하여 토큰 기반 인증 구조를 구현하면서 GenericFilterBean과 OncePerRequestFilter로 구현한 코드를 보게 되었다. 그래서 두 방식의 차이점을 아래에서 비교해 보고자 한다.
🧾 Filter
위 그림은 Spring MVC에서 요청의 lifecycle을 나타낸 그림이다.
javax.servlet-api나 tomcat-embed-core를 사용하면 제공되는 Servlet Filter Interface로서 클라이언트의 서블릿 요청을 가장 먼저 받는다.
✅ Filter interface
package jakarta.servlet;
import java.io.IOException;
public interface Filter {
default void init(FilterConfig filterConfig) throws ServletException {
}
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException;
default void destroy() {
}
}
🧾 GenericFilterBean
Spring에서 제공하는 확장된 Filter로서 Spring의 설정 정보를 가져올 수 있게 확장된 추상 클래스
public abstract class GenericFilterBean implements Filter, BeanNameAware, EnvironmentAware,
EnvironmentCapable, ServletContextAware, InitializingBean, DisposableBean {
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private String beanName;
@Nullable
private Environment environment;
@Nullable
private ServletContext servletContext;
@Nullable
private FilterConfig filterConfig;
private final Set<String> requiredProperties = new HashSet<>(4);
...
💥 문제점
Filter와 GenericFilterBean은 둘 다 매 서블릿마다 호출된다. 서블릿은 사용자의 요청을 받으면 서블릿을 생성해 메모리에 저장해 두고, 같은 클라이언트의 요청을 받으면 생성해 둔 서블릿 객체를 재활용하여 요청을 처리한다.
문제는 필터가 2번씩 적용되는 경우다.
일반적으로 Spring Security에서 인증과 접근 제어 기능이 Filter로 구현된다. 이러한 인증과 접근 제어 기능은 서블릿 간에 흐름을 동적으로 연결시켜주는 Dispatch가 이루어진다. 여기서 "API 1 Redirect"가 수행되는데, 결과적으로 다시 Filter chain을 거쳐 여러 번 인증처리가 수행되는 것이다. 이것은 한 번의 클라이언트 요청에 대해 흐름상 두 번 요청하게 되어
자원 낭비가 발생하는 결과로 이어진다. 이러한 문제를 해결하기 위해서 OncePerRequestFilter가 등장했다.
🧾 OncePerRequestFilter
Spring에서 제공하는 확장된 Filter로서 모든 서블릿에서 일관된 요청을 처리할 수 있는 추상 클래스
해당 추상 클래스를 구현한 필터는 doFilterInternal 메서드를 구현하여 사용자의 요청 당 한 번만 실행되는 필터를 만들 수 있다.
@Slf4j
@Component
public class CustomFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// TODO 전처리
filterChain.doFilter(request , response);
// TODO 후처리
}
}
GenericFilterBean과 OncePerRequestFilter 둘 다 대상을 필터로 등록해 주는 인터페이스
Refences
https://velog.io/@jmjmjmz732002/Springboot-OncePerRequestFilter-vs-GenericFilterBean
https://g4daclom.tistory.com/115
https://velog.io/@dev_tmb/JWT-%ED%86%A0%ED%81%B0-%EC%9D%B8%EC%A6%9D-%ED%94%8C%EB%A1%9C%EC%9A%B0