[공부정리] OncePerRequestFilter vs GenericFilterBean

jeyong·2024년 1월 24일
0

공부 / 생각 정리  

목록 보기
8/120
post-custom-banner


스프링에 대해서 여러가지 공부를 하던중, 정리 해놓으면 좋을 것 같은 주제를 정리하려고 한다.
이번에 다를 주제는 OncePerRequestFilter vs GenericFilterBean이다.
해당 주제를 다루게 된 이유는 Filter에 대해서 공부하던 중에
GenericFilter와 OncePerRequestFilter를 발견하게 되었고, 딱히 구현에 있어서 큰 차이점은 없어보이지만 왜 다른이름으로 사용되는지 궁금하여 공부해보았고 해당 내용을 정리하여 기록해보려고 한다.

1. GenericFilterBean

1-1. Spring MVC request lirecycle

우리가 자세히 봐야하는건 해당 사진에서 Filter에 대한 부분이다. Filter에 대해 간단히 설명하자면 아래와 같다.

  • javax.servlet-api나 tomcat-embed-core를 사용하면 제공되는 Servlet Filter Interface이다.
  • DispatcherServlet가 요청을 받기 전 앞단에 Filter에서 먼저 request를 받는다.

Filter

public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException;

    default void destroy() {
    }
}

Filter 인터페이스를 구현하고 등록하면 서블릿 컨테이너가 필터를 싱글톤 객체로 생성하고 관리한다.

  • init() : 필터 초기화 메소드, 서블릿 컨테이너가 생성될 때 호출된다.
  • doFilter() : 클라이언트 요청이 올 때마다 해당 메소드를 호출한다. 필터의 로직을 구현하면 된다.
  • destroy() : 필터 종료 메소드, 서블릿 컨테이너가 종료될 때 호출된다.

1-3. GenericFilterBean

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);
  ...
  public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

GenericFilterBean은 Filter를 implements 받아 구현한 클래스이다.

  • Filter를 확장하여 Spring에서 제공하는 filter
  • 기존 Filter에서 얻어올 수 없는 정보였던 Spring의 설정 정보를 가져올 수 있게 확장된 추상 클래스
  • 해당 Filter들은 서블릿마다 호출이 된다.
  • 서블릿은 사용자의 요청을 받으면 서블릿을 생성해 메모리에 저장해두고, 같은 클라이언트의 요청을 받으면 생성해둔 서블릿 객체를 재활용하여 요청을 처리한다.

2. OncePerRequestFilter

앞에서 GenericFilterBean만을 공부하였을때는 완벽해 보인다. 하지만 완벽하다면 OncePerRequestFilter가 탄생할 이유가 없었겠지만말이다.

  • OncePerRequestFilter가 생겨난 이유는 의도치 않은 경우에 Filter가 두번씩 적용되는 경우가 있을 수 있기 때문이다.
  • 해당 문제는 Spring Security에서 인증과 인가에서 발생할 수 있다.
  • 첫번째 API에서 요청을 처리하고 두번째 API로 redirect 시킨다고 가정하자. 그렇게 처리할 경우, 클라이언트는 한번의 요청을 한 것 뿐이지만 흐름상 요청을 두번한 것과 같이 처리 될 것이고 Filter가 두번씩 적용되는 문제가 발생한다. 해당 문제를 해결하기 위해 OncePerRequestFilter가 탄생하였다!
public class FirstFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        filterChain.doFilter(request , response);
    }
}
  • 해당 필터는 사용자의 요청당 한번만 실행되는 필터를 만들도록 해준다.
  • GenericFilterBean을 상속하여 구현한 경우 doFilter메서드를 구현하면 되고, OncePerRequestFilter를 상속하여 구현한 경우 doFilterInternal 메서드를 구현하면 된다.

3. 마무리

JwtAuthenticationFilter 구현시에는 Filter가 두번씩 적용되는 경우가 있을 수 있기 때문에 OncePerRequestFilter을 사용하는 것이 적절하다.

profile
노를 젓다 보면 언젠가는 물이 들어오겠지.
post-custom-banner

0개의 댓글