Technically Feasible

Using Servlet Filter and Spring Web with Jetty

Likeness of Michael Oldroyd
Michael Oldroyd
⚠️ This content was imported from a previous incarnation of this blog, and may contain formatting errors

I've been experimenting with servlet filter, along the same lines as my experimentation with aspects. Aspects are quite an interesting topic, however for the request instrumention task it seems that filters are much more suitable. Realising your approach is wrong and pivoting is, I feel, an important skill to learn in software development.

I must point out something up-front. In writing the example for this article, I came to the realisation that spring boot takes care of a lot. I decided to write these examples without using spring boot, in hope that I would learn more about how servlets and containers work — I wasn't disappointed. It handles all the complexities of servlet initialisation, filter registration, embedded servlet containers and so much more.

Registering Servlet Filters with Spring #

With Spring Boot, you may define an implementation of Filter as a @Bean. A Spring Boot application will—by default—register this as a servlet filter. Alternately, you can define a FilterRegistrationBean which allows you to modify the filter configuration, such as path matching and execution ordering. If you do both, spring seems to automatically register the FilterRegistrationBean over the Filter, giving you a great deal of flexibility.

@Bean
public FilterRegistrationBean getExampleFilter(ExampleServletFilter exampleServletFilter){
  FilterRegistrationBean registrationBean
    = new FilterRegistrationBean<>();
  registrationBean.setFilter(exampleServletFilter);
  registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
  return registrationBean;
}

With Spring Web, you must register a filter before a ContextLoaderListener initializes the context. The servlet context must become read-only after being initialised, except as dictated by the Servlet 3 specification section 4.4. WebApplicationInitializer::onStartup is typically used to initialize both the application and servlet contexts, so filters must be registered during this process. Normally, this would stop you from registering bean instances as filters from the spring IoC container. Spring provides DelegatingFilterProxy to allow spring-managed beans be used as filters, as demonstrated below;

DelegatingFilterProxy exampleServletFilter = new DelegatingFilterProxy("exampleServletFilter");
servletContext.addFilter("exampleServletFilter", exampleServletFilter)
  .addMappingForUrlPatterns(
    EnumSet.of(DispatcherType.REQUEST),
    true,
    "/example-filtered/*",
    "/example-exception/*"
  );

You must refer to your bean by a defined name, rather than it's Class<>. The initialization is the main difference. Your application code must set up any Filter up front, whereas with Spring Boot this can be wired up in configuration or external dependencies.

A note on Servlet Filter Ordering #

Spring Boot's FilterRegistrationBean and @Bean support explicit ordering. This is demonstrated above, using FilterRegistrationBean::setOrder, or alternately the @Order annotation. Servlet filters don't support ordering when using Java-based servlet configuration, which means that there's no explicit way to order filters in our example.

Image of me

Michael Oldroyd

Michael is a Software Engineer working in the North West of England.