Using multiple dispatcher servlets / web contexts with spring boot

31,560

Solution 1

As @josh-ghiloni already said, you need to register a ServletRegistrationBean for every isolated web context you want to create. You need to create an application context from a xml or java config class. You can use @Import and @ComponentScan annotation to add shared services to the parent context. Here is an example:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;


//@ComponentScan({"..."})
//@Import({})
public class Starter {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Starter.class, args);
    }

    @Bean
    public ServletRegistrationBean apiV1() {
        DispatcherServlet dispatcherServlet = new DispatcherServlet();

        XmlWebApplicationContext applicationContext = new XmlWebApplicationContext();
        applicationContext.setConfigLocation("classpath:/META-INF/spring/webmvc-context.xml");
        dispatcherServlet.setApplicationContext(applicationContext);

        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/api/1/*");
        servletRegistrationBean.setName("api-v1");

        return servletRegistrationBean;
    }

    @Bean
    public ServletRegistrationBean apiV2() {
        DispatcherServlet dispatcherServlet = new DispatcherServlet();

        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
        applicationContext.register(ResourceConfig.class);
        dispatcherServlet.setApplicationContext(applicationContext);

        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/api/2/*");
        servletRegistrationBean.setName("api-v2");
        return servletRegistrationBean;
    }
}

Solution 2

Create a ServletRegistrationBean that declares the servlet and its mappings. You will probably also want to exclude DispatcherServletAutoConfiguration from the autoconfigurations called, because it will register a DispatcherServlet at / and override yours

EDIT Despite my comment below saying you might not need this, unless you need your APIs running on separate ports (and it doesn't sound like you do), Dave Syer, one of the authors of Spring Boot, answered a very similar question here: Configure multiple servletcontainers/servlets with spring boot

Share:
31,560
Jan
Author by

Jan

Outdoor sport enthusiast and nerd. You too? Lets work together! http://www.komoot.de/jobs

Updated on January 03, 2021

Comments

  • Jan
    Jan over 3 years

    I created a spring boot application with a parent context (services) and child context (spring-webmvc controllers):

    @Configuration
    public class MainApiApplication {
    
        public static void main(String[] args) {
            new SpringApplicationBuilder()
                    .parent(Services.class)
                    .child(ApiOne.class, MainApiApplication.class)
                    .run(args);
        }
    
        @Bean
        public EmbeddedServletContainerFactory servletContainer() {
            return new TomcatEmbeddedServletContainerFactory();
        }
    
    }
    

    Now I want to add another client context (and DispatcherServlet) for my ApiTwo.class configuration. I think I have to do two things:

    1. Move the servletContainer (thus the MainApiApplication.class configuration) out of the child context and
    2. add a path mapping /one/ -> ApiOne.class and /two/ ApiTwo.class

    What is the spring boot way to do it?