Filter는 Spring이 아닌 J2EE 표준 스펙으로 Dispatcher Servlet에 요청이 전달되기 전/후에 url 패턴에 맞는 요청에 대해 부가작업을 처리할 수 있는 기능을 제공한다고 합니다.
@Component
class LoggingFilter(private val mapper: ObjectMapper) : Filter {
override fun doFilter(
request: ServletRequest?,
response: ServletResponse?,
chain: FilterChain?,
) {
...
}
}
하지만 저는 Filter 클래스를 주로 위와 같이 빈으로 등록하여 사용하고 있었기에 Spring에서 Filter를 관리하고 있다 착각하고 있었는데 이에 대해 간단히 정리해보려 합니다.
ServeltContext에 등록되는 필터
Spring에서 Filter 클래스는 FilterRegistrationBean과 DelegatingFilterProxyRegistrationBean를 통해 스프링 컨텍스트의 빈으로 등록됩니다.
그렇게 등록된 Filter 빈의 경우 Tomcat(ServeltContainer)이 시작되는 과정에서 ServeltContext에 등록됩니다.
// RegistrationBean line 45 ~ 53
@Override
public final void onStartup(ServletContext servletContext) throws ServletException {
String description = getDescription();
if (!isEnabled()) {
logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
return;
}
register(description, servletContext);
}
// AbstractFilterRegistrationBean line 228 ~ 231
@Override
protected Dynamic addRegistration(String description, ServletContext servletContext) {
Filter filter = getFilter();
return servletContext.addFilter(getOrDeduceName(filter), filter);
}
이때 Filter 클래스를 등록한 빈의 종류에 따라 getFilter 메서드의 동작이 달라집니다.
FilterRegistrationBean의 경우 FilterRegistrationBean에 등록된 Filter 클래스를 반환하는 반면 DelegatingFilterProxyRegistrationBean의 경우 Filter 클래스가 아닌 아래와 같이 DelegatingFilterProxy를 생성하여 반환합니다.
@Override
public DelegatingFilterProxy getFilter() {
return new DelegatingFilterProxy(this.targetBeanName, getWebApplicationContext()) {
@Override
protected void initFilterBean() throws ServletException {
// Don't initialize filter bean on init()
}
};
}
DelegatingFilterProxy에 대한 생각
Unlike the FilterRegistrationBean, referenced filters are not instantiated early. In fact, if the delegate filter bean is marked @Lazy it won't be instantiated at all until the filter is called.
주석에 따르면 DelegatingFilterProxy는 즉시 FilterRegistrationBean의 필터와 달리 즉시 초기화되지 않는다고 합니다.
대신 해당 Filter가 불려질 때 초기화 된다고 합니다.
DelegatingFilterProxy로 등록되는 대표적인 Filter로는 Spring Security Filter Chain이 있습니다.
제가 생각하기에 Security Filter Chain을 DelegatingFilterProxy로 등록하는 이유는 Tomcat이 FilterChain을 요청당 만들기 때문에 Security Filter Chain를 즉시 초기화하기보다는 DelegatingFilterProxy로 등록하여 사용될 때 초기화 될 수 있도록 한 것이 아닐까 합니다.
// StandardWrapperValve line 141
// Create the filter chain for this request
ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
아직은 Security Filter Chain처럼 매 요청마다 초기화하는 것이 부담 스러울 Filter를 사용해 본 적은 없는데 그러한 상황이 생긴다면 Filter 클래스를 DelegatingFilterProxyRegistrationBean로 등록하는 것을 고려할 것 같습니다.
'스프링' 카테고리의 다른 글
BeanPostProcessor (1) | 2025.01.16 |
---|---|
@Async 정리 (0) | 2025.01.02 |
이벤트 리스너 정리 (0) | 2025.01.02 |
@EnableWebMvc를 붙이지 않은 이유 (0) | 2024.09.23 |
SpringBoot에서 HTTP 요청을 처리하는 과정을 살펴보며 (DispatcherServlet) (0) | 2024.08.26 |