1. OVERVIEW

Let’s say you find yourself modernizing a legacy Java web application, not just the UI libraries but also the middleware. And let’s say that Spring Boot was the selected framework to get the job done because of its many advantages:

  • Allows teams getting started quickly reducing boilerplate code.
  • Provides starter projects which extremely reduces Maven configuration, especially dependencies management.
  • Production ready actuator endpoints reporting metrics, health check.
  • Provides opiniated autoconfiguration out of the box flexible enough to be overriden when needed.
  • Seamless integration with the Spring ecosystem.

How can you add a Filter, a Servlet, and a Listener to a Spring Boot application now that it lacks the web.xml file descriptor? This post answers this question also covering injecting dependencies to a Filter, Servlet, or Listener.

2. REQUIREMENTS

  • Java 7+.
  • Maven 3.2+.
  • Familiarity with Spring Framework.

3. APPLICATION DEPENDENCIES

pom.xml:

...
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.5.10.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
</parent>
...
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
...
<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    ...
  </plugins>
  ...
</build>
...

spring-boot-starter-web transitively includes dependencies required to implement a Filter, Servlet or Listener.

spring-boot-maven-plugin allows Spring Boot applications to be packages as a jar or war archive and it from command line using Maven or Gradle. Visit the spring-boot-maven-plugin page to learn more.

4. SERVLETS

4.1. IMPLEMENTING A SERVLET

package com.asimio.web.servlet;
...
public class AsimioTechServlet extends HttpServlet {
...
  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    ...
  }

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    ...
  }
}

A very simple Servlet.

4.2. REGISTERING A SERVLET

Let’s register it using Spring Boot’s ServletRegistrationBean:

package com.asimio.main;
...
@Configuration
public class AppConfig {
  ...
  @Bean
  public ServletRegistrationBean<AsimioTechServlet> asimioTechServletRegistrationBean() {
    ServletRegistrationBean<AsimioTechServlet> result = new ServletRegistrationBean<>(
      new AsimioTechServlet(), "/<url-map>");  // Comma separated url paths.
    result.setName("asimioTechServlet");
    result.setOrder(1);
    ...
    return result;
  }
...
}

Spring Boot beans are instantiated in @Configuration-annotated classes. If more than one servlet is going to be registered then the name for each ServletRegistrationBean bean would have to be explicitly set in @Bean annotations.

5. FILTERS

5.1. IMPLEMENTING A FILTER

package com.asimio.web.filter;
...
public class AsimioTechFilter implements Filter {

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

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
	...	
  }

  @Override
  public void destroy() {
    ...
  }
}

An ordinary Servlet Filter.

5.2. REGISTERING A FILTER

Let’s now register a couple of Filters using Spring Boot’s FilterRegistrationBean:

...
@Bean
public FilterRegistrationBean<SiteMeshFilter> sitemeshFilterRegistrationBean() {
  FilterRegistrationBean<SiteMeshFilter> result = new FilterRegistrationBean<>(new SiteMeshFilter());
  result.setName("sitemeshFilter");
  result.addUrlPatterns("*.html");  // Comma separated url patterns.
  result.setOrder(1);
  return result;
}

@Bean
public FilterRegistrationBean<AsimioTechFilter> asimioTechFilterRegistrationBean() {
  FilterRegistrationBean<AsimioTechFilter> result = new FilterRegistrationBean<>(new AsimioTechFilter());
  result.setName("asimioTechFilter");
  result.addServletRegistrationBeans(
    Arrays.asList(this.asimioTechServletRegistrationBean()));  // List of ServletRegistrationBean
  result.setOrder(2);
  ...
  return result;
}
...
}

Again, if more than one filter is going to be registered then the name for each FilterRegistrationBean bean would have to be explicitly set in @Bean annotations. Also notice that similar to how they could be configured in web.xml, Filters could be mapped to url patterns as well as to servlets in Spring Boot web applications.

6. LISTENERS

6.1. IMPLEMENTING A LISTENER

package com.asimio.web.listener;
...
public class AsimioTechServletContextListener implements ServletContextListener {

  @Override
  public void contextInitialized(ServletContextEvent e) {
    ...
  }

  @Override
  public void contextDestroyed(ServletContextEvent e) {
    ...
  }
}

Another simple Servlet Listener implementation.

6.2. REGISTERING A LISTENER

A Java web application Servlet Listener could be registered using Spring Boot’s ServletListenerRegistrationBean:

...
@Bean
public ServletListenerRegistrationBean<ServletContextListener> asimioTechServletContextListenerRegistrationBean() {
  ServletListenerRegistrationBean<ServletContextListener> result =  new ServletListenerRegistrationBean<>();
  result.setListener(new AsimioTechServletContextListener());
  result.setName("asimioTechServletContextListenerRegistrationBean");
  result.setOrder(1);
  ...
  return result;
}
...

As a reminder, if more than one listener is going to be registered then the name for each ServletListenerRegistrationBean bean would have to be set in each listener @Bean annotation.

Also worth mentioning if you need to use a common set of Filters, Servlets and / or Listeners in multiple Spring Boot applications, you could pack them in their own custom Spring Boot starter and include it in Spring Boot applications with minimal configuration.

Thanks for reading and as always, feedback is very much appreciated. If you found this post helpful and would like to receive updates when content like this gets published, sign up to the newsletter.