Search code examples
springspring-bootfilterinterceptor

Why Servlet Filter can be Spring Bean?


What i know about Filter and Interceptor is that Filters as J2EE Specifications are part of the webserver and not the Spring framework. So some older articles explain that it is impossible to register filters as Spring Bean while Interceptor is possible. But the results I got when I tested today is that Filters can be Spring Bean and also inject Spring Bean on Filters are possible too like Interceptors. (I tested on SpringBoot Framework)

@Component
public class CustomFilterTest implements Filter {

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws ServletException, IOException {
        chain.doFilter(request, response);
    }

    @Override
    public void init(final FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }

}
@RestController
@RequiredArgsConstructor
public class ProductController {

    private final CustomFilterTest customFilterTest;

    @GetMapping("/test")
    public ResponseEntity<Void> temp() {
        System.out.println(customFilterTest);
        return ResponseEntity.noContent().build();
    }
}

Can anyone please explain to me?


Solution

  • We have to make a distinction between a regular Spring application and a Spring Boot application here. As with both, you can register a servlet filter as a bean, but the mechanism is a bit different.

    Spring Framework

    In plain Spring use the DelegatingFilterProxy to achieve this. The task of the DelegatingFilterProxy is to look for a bean with the same name as the filter in the root application context (the ApplicationContext registered through the ContextLoaderListener). This bean has to be your managed servlet filter.

    @Configuration
    @EnableWebMvc
    public class WebConfiguration {
    
      @Bean
      public void YourFilter myFilter() { ... }
    }
    

    Then for the web application you would register a DelegatingFilterProxy with the name myFilter to make this work.

    public class MyWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
    public void onStartup(ServletContext servletContext)
                   throws ServletException {
       super.onStartup(servletContext);
       servletContext.addFilter("myFilter", DelegatingFilterProxy.class);
    }
    

    Spring Boot

    In Spring Boot it is a bit different as Spring Boot is also in control of your servlet container, like Tomcat. It basically means that Tomcat is also a managed bean in your ApplicationContext and Spring Boot can inject dependencies into it. So when Spring Boot detects a bean for the servlet filter it will automatically add it to the filter chain (without the need of a DelegatingFilterProxy).

    Which means only an @Bean for your filter is needed.

    @Configuration
    public class WebConfiguration {
    
      @Bean
      public YourFilter myFilter() { ... }
    }
    

    Additionally you can configure things like URLs etc. by adding an additional FilterRegistrationBean for this filter.

    Conclusion

    For plain Spring the DelegatingFilterProxy has been around since Spring 1.2 which was released in 2005. This means if you are reading really, really, really old articles (before 2005) this was true, however with the addition of the DelegatingFilterProxy, this isn't anymore. With the release of Spring Boot, this became even a lesser issue, is it more or less is the only way to register a filter (as a managed bean).