Configuring boot servlet context and filters

A next step after you have bought into moving to java config and spring boot is tackling converting your web.xml to be configured programmatically. It is almost given that you will need to add an additional filters but there also might be a use case where you need to route additional servletmappings to the dispatch servlet. One migration tip is incrementally make your way by doing peeling one element or layer at at time.

At a high level, when spring boot fires up it will make its way to AbstractDispatcherServletInitializer which will register the dispatch servlet and register filters. There is a couple of ways to configure servlet mapping and filters which we will work through below.

Configuring with additional servlet mappings

Spring boot by default will map the dispatcherServlet to '/' if there is only a single servlet in context. In the example lets create an artificial requirement where infrastructure is dictating we need to handle multiple request mapping to the dispatcherServlet. Your current web.xml might look like:

<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/whatever/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/whatever2/*</url-pattern>
</servlet-mapping>

ServletRegistrationBean

ServletRegistrationBean is class with a spring bean friendly design that is used to register servlets in a servlet 3.0 container within spring boot. Within a @Configuration class, you should be able to register ServletRegistrationBean with the following configuration. This should over write the '/' request mapping and provide '{context}/whatever/' and '{context}/whatever2/'.

@Bean
public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
    ServletRegistrationBean registration = new ServletRegistrationBean(
            dispatcherServlet);
    registration.addUrlMappings("/whatever/*", "/whatever2/*");
    return registration;
}

SpringBootServletInitializer

If you looking for more control or already have a hook into the WebApplicationInitializer you could add the request mapping directly to the servlet context.

public class MyApplication implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        
        servletContext.addServlet("dispatchServlet", ...);
        
        super.onStartup(servletContext);
    }
}

Configuring additional filters

A popular compression filter used is the plantej CompressingFilter which has all the smarts on compressing data written to HttpServletResponse and if the client browser supports compression. I won't go on a tangent here and ask why doesn't your infrastructure just support compression by default vs having to add it to all of your apps?! At any rate, lets look at how we can add this compression filter to spring boot context.

Defining a filter bean

You can define a @Bean and the filter should automatically get picked up.

@Bean
public Filter compressingFilter() {
    CompressingFilter compressingFilter = new CompressingFilter();
    return compressingFilter;
}

Register with FilterRegistrationBean

If you need a bit more control than just defining the filter with @Bean annotation, you could use the FilterRegistrationBean

@Bean
public FilterRegistrationBean filterRegistrationBean () {
    
    CompressingFilter compressingFilter = new CompressingFilter();
    
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    
    registrationBean.setFilter(compressingFilter);
    
    return registrationBean;
}

ServletRegistrationBean

A third way to register a filter in spring boot, which is similar to how register a servlet mapping above, is if you have a hook to the WebApplicationInitializer you can add the filter to the servlet context.

public class MyApplication implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        setActiveProfile();
        
        servletContext.addFilter(filterName, filterClass);
        
        super.onStartup(servletContext);
    }
}

Possible gotcha with websphere

IBM Web Sphere 8.0 and above started supporting servlet 3.0 which should give you the ability to configure your application without specifying a web.xml. If you are using spring-boot, ibm websphere, and servlet 3.0 and are trying to deploy without a web.xml there might be a possible gotcha. This isn't confirmed across the board since each IBM websphere shops have a specialized custom layer on top of webpshere. When deploying to websphere 8.5, it doesn't appear that they fully support eliminating the web.xml which causes deployment issues. One workaround is creating an empty web.xml file and then set the metadata-complete="false".

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
          http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0" metadata-complete="false">
    <display-name>Servlet 3.0 Web Application</display-name>
</web-app>