在 Spring Boot 中使用多个调度程序 Servlet/Web 上下文

Posted

技术标签:

【中文标题】在 Spring Boot 中使用多个调度程序 Servlet/Web 上下文【英文标题】:Using multiple dispatcher servlets / web contexts with spring boot 【发布时间】:2015-05-19 17:30:14 【问题描述】:

我创建了一个带有父上下文(服务)和子上下文(spring-webmvc 控制器)的 Spring Boot 应用程序:

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


现在我想为我的ApiTwo.class 配置添加另一个客户端上下文(和 DispatcherServlet)。我想我必须做两件事:

    servletContainer(因此 MainApiApplication.class 配置)移出子上下文并 添加路径映射/one/ -> ApiOne.class/two/ ApiTwo.class

spring boot 的做法是什么?

【问题讨论】:

【参考方案1】:

正如@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;
    

【讨论】:

我最初想拆分赏金,因为@josh-ghiloni 发布了最初的想法,但您的帖子更完整。因为 SO 的目的是对一个问题有一个确凿的答案,所以我授予您。谢谢!您的示例中唯一缺少的部分是添加 Services.class 上下文,您可以添加它@ksokol 吗? 我投票赞成@josh-ghiloni 以表明他的正确答案。要将服务添加到父上下文,您需要添加 @Import(ServiceConfig1.class, ServiceConfig2.class)@ComponentScan("my.package.service")。看看我的例子中的第一行。 ResourceConfig.class 是什么?【参考方案2】:

创建一个声明 servlet 及其映射的ServletRegistrationBean。您可能还想从调用的自动配置中排除 DispatcherServletAutoConfiguration,因为它会在 / 注册 DispatcherServlet 并覆盖您的

编辑尽管我在下面的评论说你可能不需要这个,除非你需要在单独的端口上运行你的 API(听起来不像你这样做),Dave Syer,作者之一Spring Boot,在这里回答了一个非常相似的问题:Configure multiple servletcontainers/servlets with spring boot

【讨论】:

你能举个例子,包括 ApiOne/Two.class 上下文吗?另外,我应该将 ServletRegistrationBean 放在当前注册服务的父上下文中的什么位置? 当我阅读您的问题时,我不确定您是否需要多个 DispatcherServlet。这背后的原因是什么?您可以轻松地让两个 Api Controllers 和谐相处。您只需将 @RequestMapping("/one") 添加到 ApiOne 类,将 @RequestMapping("/two") 添加到 ApiTwo 类即可。 它们有冲突的错误处理程序和消息转换器配置。我更愿意将它们彼此分开,就像几年前在基于 web.xml 的项目中所做的那样。 我明白了——您可能想阅读我当时链接的 Dave 的答案,这可能会对您有所帮助。

以上是关于在 Spring Boot 中使用多个调度程序 Servlet/Web 上下文的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot + 调度程序 + Spring Data JPA + Oracle 中的异常处理

Spring Boot 批处理调度程序运行一次

如何使用 Spring Boot 和 Flyway 为 Quartz 调度程序设置数据库模式?

SpringBoot任务调度

在spring boot微服务中,休息调用的调度不工作。

如何在 spring-boot 应用程序中配置多个 Keycloak sso 客户端?