68
votes

I have an extra servlet I need to register in my application. However with Spring Boot and its Java Config, I can't just add servlet mappings in a web.xml file.

How can I add additional servlets?

7
I came up to this question just now, but if you don't mind, what will be the purpose to add other Servlets apart from the provided DispatcherServlet? You can use anyway multiple Controllers and whatever url/path you want - Aerox
@aerox It has been many years... I can't recall the usecase I had at the time. Perhaps it was to leverage the DropWizard metric exporter servlet, since it offered a way to visualize the metric that had been collected. SpringBoot later incoporated that into an actuator endpoint itself. (And Micrometer.io solves the problem even better) - checketts

7 Answers

59
votes

Just add a bean for the servlet. It'll get mapped to /{beanName}/.

@Bean
public Servlet foo() {
    return new FooServlet();
}
140
votes

Also available is the ServletRegistrationBean

@Bean
public ServletRegistrationBean servletRegistrationBean(){
    return new ServletRegistrationBean(new FooServlet(),"/someOtherUrl/*");
}

Which ended up being the path I took.

22
votes

You can register multiple different servlet with different ServletRegistrationBean like @Bean in Application class and you can register a servlet has multiple servlet mapping;

   @Bean
   public ServletRegistrationBean axisServletRegistrationBean() {
      ServletRegistrationBean registration = new ServletRegistrationBean(new AxisServlet(), "/services/*");
      registration.addUrlMappings("*.jws");
      return registration;
   }

   @Bean
   public ServletRegistrationBean adminServletRegistrationBean() {
      return new ServletRegistrationBean(new AdminServlet(), "/servlet/AdminServlet");
   }
5
votes

We can also register the Servlet as follow way:

@Configuration
public class ConfigureWeb implements ServletContextInitializer, EmbeddedServletContainerCustomizer {

  @Override
  public void onStartup(ServletContext servletContext) throws ServletException {
      registerServlet(servletContext);
  }

  private void registerServlet(ServletContext servletContext) {
      log.debug("register Servlet");
      ServletRegistration.Dynamic serviceServlet = servletContext.addServlet("ServiceConnect", new ServiceServlet());

      serviceServlet.addMapping("/api/ServiceConnect/*");
      serviceServlet.setAsyncSupported(true);
      serviceServlet.setLoadOnStartup(2);
  }
}
4
votes

If you're using embedded server, you can annotate with @WebServlet your servlet class:

@WebServlet(urlPatterns = "/example")
public class ExampleServlet extends HttpServlet

From @WebServlet:

Annotation used to declare a servlet.

This annotation is processed by the container at deployment time, and the corresponding servlet made available at the specified URL patterns.

And enable @ServletComponentScan on a base class:

@ServletComponentScan
@EntityScan(basePackageClasses = { ExampleApp.class, Jsr310JpaConverters.class })
@SpringBootApplication
public class ExampleApp 

Please note that @ServletComponentScan will work only with embedded server:

Enables scanning for Servlet components (filters, servlets, and listeners). Scanning is only performed when using an embedded web server.

More info: The @ServletComponentScan Annotation in Spring Boot

2
votes

This way worked for me, having a servlet called WS01455501EndpointFor89

@Bean
public ServletRegistrationBean<WS01455501EndpointFor89> servletRegistrationBeanAlt(ApplicationContext context) {
    ServletRegistrationBean<WS01455501EndpointFor89> servletRegistrationBean = new ServletRegistrationBean<>(new WS01455501EndpointFor89(),
            "/WS01455501Endpoint");
    servletRegistrationBean.setLoadOnStartup(1);
    return servletRegistrationBean;
}
0
votes

Also available in the BeanDefinitionRegistryPostProcessor

package bj;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@SpringBootApplication
class App implements BeanDefinitionRegistryPostProcessor {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        registry.registerBeanDefinition("myServlet", new RootBeanDefinition(ServletRegistrationBean.class,
                () -> new ServletRegistrationBean<>(new HttpServlet() {
                    @Override
                    protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
                        resp.getWriter().write("hello world");
                    }
                }, "/foo/*")));
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    }
}