Использование нескольких диспетчерских сервлетов/веб-контекстов с весенней загрузкой

Я создал загрузочное приложение Spring с родительским контекстом (службы) и дочерним контекстом (контроллеры Spring-webmvc):

@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();
    }

}

Теперь я хочу добавить еще один клиентский контекст (и DispatcherServlet) для моей конфигурации ApiTwo.class. Я думаю, что я должен сделать две вещи:

  1. Переместите servletContainer (таким образом, конфигурацию MainApiApplication.class) из дочернего контекста и
  2. добавить сопоставление пути /one/ -> ApiOne.class и /two/ ApiTwo.class

Как это сделать с весенней загрузкой?


person Jan    schedule 17.03.2015    source источник


Ответы (2)


Как уже сказал @josh-ghiloni, вам нужно зарегистрировать ServletRegistrationBean для каждого изолированного веб-контекста, который вы хотите создать. Вам необходимо создать контекст приложения из класса конфигурации xml или java. Вы можете использовать аннотации @Import и @ComponentScan для добавления общих служб в родительский контекст. Вот пример:

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;
    }
}
person ksokol    schedule 22.03.2015
comment
Первоначально я хотел разделить награду, потому что @josh-ghiloni опубликовал первоначальную идею, но ваш пост более полный. Поскольку цель SO состоит в том, чтобы иметь один окончательный ответ на один вопрос, я предоставляю его вам. Спасибо! Единственная недостающая часть в вашем примере — добавить контекст Services.class, не могли бы вы добавить его @ksokol? - person Jan; 27.03.2015
comment
Я проголосовал за @josh-ghiloni, чтобы указать его правильный ответ. Чтобы добавить службы в родительский контекст, вам нужно добавить @Import({ServiceConfig1.class, ServiceConfig2.class}) или @ComponentScan("my.package.service"). Взгляните на первые строки в моем примере. - person ksokol; 27.03.2015
comment
что такое ResourceConfig.class? - person Arpan; 26.12.2019

Создайте ServletRegistrationBean, который объявляет сервлет и его сопоставления. Возможно, вы также захотите исключить DispatcherServletAutoConfiguration из вызываемых автоконфигураций, потому что он зарегистрирует DispatcherServlet в / и переопределит ваш

EDIT Несмотря на мой комментарий ниже о том, что вам это может не понадобиться, если только вам не нужны ваши API, работающие на отдельных портах (и это не похоже на то, что вы делаете), Дэйв Сайер, один из авторов Spring Boot , ответил на очень похожий вопрос здесь: Настроить несколько сервлетконтейнеров/сервлетов с весенней загрузкой

person Josh Ghiloni    schedule 19.03.2015
comment
Можете ли вы привести пример, включая контексты ApiOne/Two.class? Кроме того, где я должен разместить ServletRegistrationBean в родительском контексте, где в настоящее время зарегистрированы мои службы? - person Jan; 19.03.2015
comment
Когда я прочитал ваш вопрос, я не уверен, что вам нужно несколько DispatcherServlets. Что стоит за этим? Вы можете легко иметь два Api Controller, живущих в гармонии друг с другом. Вы можете просто добавить @RequestMapping("/one") к классу ApiOne и @RequestMapping("/two") к классу ApiTwo. - person Josh Ghiloni; 19.03.2015
comment
Они имеют конфликтующие обработчики ошибок и конфигурации преобразователя сообщений. Я бы предпочел отделить их друг от друга, как я сделал это в проекте на основе web.xml несколько лет назад. - person Jan; 20.03.2015
comment
Ясно - вы можете прочитать ответ Дейва, который я тогда связал, это может вам помочь. - person Josh Ghiloni; 20.03.2015