OncePerRequestFilter와 Filter의 차이

OncePerRequestFilter와 Filter

spring-request-lifecycle

스프링 MVC에서 리퀘스트의 라이프 사이클을 보여주는 그림이다. (너무 많이 봐서 지겹다 이제는)

Filterjavax.servlet-apitomcat-embed-core를 사용하면 제공되는 Servlet Filter Interface이다.

역할은 사용자의 서블릿 리퀘스트를 가장 최전선에서 받을 때 사용한다.

그러다 문득 FilterOncePerRequestFilter의 차이가 궁금해졌다.

FilterInterceptor의 차이라면 익히 알고 있지만, OncePerRequestFilterFilter의 차이가 뭔지 궁금하더라.

오늘은 이 둘의 차이점에 대해서 학습한 것에 대해 정리해두려고 한다.

OncePerRequestFilter를 이야기하기에 앞서 우리는 Filter가 어떻게 동작하는지부터 이해해야한다.

class LoggingFilter : Filter {
    override fun doFilter(request: ServletRequest?, response: ServletResponse?, chain: FilterChain?) {
        // do Filter 실행 전 로직
        println("Before")
        chain?.doFilter(request, response) ?: throw Exception()
        // do Filter 실행 후 로직
        println("After")
    }
}

위 코드에서 Before라는 문자열이 출력되는 코드가 서블릿 전에 실행되고 서블릿이 실행된 이후 After라는 문자열이 출력될 것이다.

여기까지는 다 아는 내용일 것이다.

Filter를 조금 더 확장하여 스프링에서 제공하는 필터가 있는데 그것이 바로 GenericFilterBean이다.

GenericFilterBean은 기존 Filter에서 얻어올 수 없는 정보였던 Spring의 설정 정보를 가져올 수 있게 확장된 추상 클래스이다.

내부를 까보면 이것 저것 얻어올 수 있는 정보가 꽤 있다는 사실을 알 수 있다. (setter 메서드가 있어서 정보 저장도 가능)

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);

    ...

이 두 필터는 한 가지 공통점이 있는데 매 서블릿 마다 호출이 된다는 것이다.

안다. 나도 처음에 이게 의미하는 것이 뭔지 몰라서 처음에 좀 이해하기가 어려웠다.

그러니 최대한 쉽게 설명하자면 다음과 같다.

서블릿은 사용자의 요청을 받으면 서블릿을 생성해 메모리에 저장해두고, 같은 클라이언트의 요청을 받으면 생성해둔 서블릿 객체를 재활용하여 요청을 처리한다.

여기까지는 서블릿의 기본적인 내용이다.

문제는 이 서블릿이 다른 서블릿으로 dispatch되는 경우가 있을 수 있다.

가장 대표적으로 Spring Security에서 인증과 접근 제어 기능이 Filter로 구현되어진다.

이러한 인증과 접근 제어는 RequestDispatcher 클래스에 의해 다른 서블릿으로 dispatch되게 되는데, 이 때 이동할 서블릿에 도착하기 전에 다시 한번 filter chain을 거치게 된다.

바로 이 때 또 다른 서블릿이 우리가 정의해둔 필터가 FilterGenericFilterBean로 구현된 filter를 또 타면서 필터가 두 번 실행되는 현상이 발생할 수 있다.

이런 문제를 해결하기 위해 등장한 것이 바로 이번 글의 주인공인 OncePerRequestFilter이다.

OncePerRequestFilter는 그 이름에서도 알 수 있듯이 모든 서블릿에 일관된 요청을 처리하기 위해 만들어진 필터이다.

이 추상 클래스를 구현한 필터는 사용자의 한번에 요청 당 딱 한번만 실행되는 필터를 만들 수 있다. (이름 참 잘 지었다)

Reference

https://stackoverflow.com/questions/13152946/what-is-onceperrequestfilter



© 2022. by minkuk

Powered by minkuk