gpt4 book ai didi

spring-mvc - 如何在模块化 Spring Boot 应用程序中定义隔离的 Web 上下文?

转载 作者:行者123 更新时间:2023-12-04 03:05:28 25 4
gpt4 key购买 nike

给定一个由引导模块和两个或多个独立的业务模块组成的 Spring Boot 应用程序 - 每个模块都公开特定于业务域的 REST API,并且每个模块都使用独立的、隔离的文档存储来进行数据持久性,我该怎么做关于配置这样的应用程序,例如:

  • 引导模块定义了一个父上下文(非 Web),它为底层模块(全局配置、对象映射器等)提供某些共享资源
  • 每个业务模块都在同一个端口上公开它们的 REST Controller ,但使用不同的上下文路径。理想情况下,我希望能够为每个模块(例如/api/catalog、/api/orders)定义一个基本路径,并在每个 Controller 中单独定义子路径。
  • 每个业务模块定义自己的存储库配置(例如每个模块的不同 MongoDB 设置)

  • 为了隔离各个业务模块的上下文(这允许我在每个模块中管理独立的存储库配置),我尝试使用 SpringApplicationBuilder 中可用的上下文层次结构来隔离每个单独的业务模块的上下文:
    public class Application {

    @Configuration
    protected static class ParentContext {
    }

    public static void main(String[] args) throws Exception {
    new SpringApplicationBuilder(ParentContext.class)
    .child(products.config.ModuleConfiguration.class)
    .web(true)
    .sibling(orders.config.ModuleConfiguration.class)
    .web(true)
    .run(args);
    }
    }

    然而,由于每个模块都包含一个使用 @EnableAutoConfiguration 注释的配置类,这会导致 Spring Boot 尝试启动两个独立的嵌入式 servlet 容器,每个容器都尝试绑定(bind)到同一个端口:
    @Configuration
    @EnableAutoConfiguration
    public class WebApplicationConfiguration {

    @Value("${api.basePath:/api}")
    protected String apiBasePath;

    @Bean
    public DispatcherServlet dispatcherServlet() {
    return new DispatcherServlet();
    }

    @Bean
    public ServletRegistrationBean dispatcherServletRegistration() {
    ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet(),
    apiBasePath + "/products/*");
    registration.setName(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);

    return registration;
    }
    }

    关于上下文层次结构的 Spring Boot 文档指出父上下文不能是 Web 上下文,所以我对如何在隔离的子上下文之间共享嵌入式 servlet 容器有点迷茫。

    我创建了一个最小的 GitHub项目来说明这一点:

    最佳答案

  • 为业务模块 child1 的上下文创建配置类
    package com.child1;
    @Configuration
    @ComponentScan(basePackages = {"com.child1a", "com.child1b"})
    public class Child1Configuration {
    }
  • 为业务模块 child2 的上下文创建配置类
    package com.child2;
    @Configuration
    @ComponentScan(basePackages = {"com.child2a", "com.child2b"})
    public class Child2Configuration {

    }
  • 为引导模块父上下文创建一个配置类。指定组件扫描要由子上下文共享的 bean
    package com.parent;
    @Configuration
    @ComponentScan(basePackages = {"com.parent1", "com.root"})
    public class ParentConfiguration {

    }
  • 使用两个调度程序 servlet bean 创建 SpringBootApplication 类,每个业务模块一个。为每个 servlet 创建应用程序上下文,并将引导应用程序创建的上下文设置为 root。基本上 spring 会将上下文注入(inject)到 @Bean 方法的 ApplicationContext 参数中。
    package com.parent;
    @SpringBootApplication
    public class Application {

    public static void main(String[] args) {
    ApplicationContext context = SpringApplication.run(Application.class, args);
    }

    @Bean
    public ServletRegistrationBean child1(ApplicationContext parentContext) {

    DispatcherServlet dispatcherServlet = new DispatcherServlet();
    dispatcherServlet.setDetectAllHandlerMappings(false);

    AnnotationConfigWebApplicationContext applicationContext = new
    AnnotationConfigWebApplicationContext();
    applicationContext.setParent(parentContext);
    applicationContext.register(Child1Configuration.class);

    applicationContext.refresh();

    dispatcherServlet.setApplicationContext(applicationContext);

    ServletRegistrationBean servletRegistrationBean = new
    ServletRegistrationBean(dispatcherServlet, true, "/child1/*");

    servletRegistrationBean.setName("child1");

    servletRegistrationBean.setLoadOnStartup(1);

    return servletRegistrationBean;
    }

    @Bean
    public ServletRegistrationBean child2(ApplicationContext parentContext) {



    DispatcherServlet dispatcherServlet = new DispatcherServlet();
    dispatcherServlet.setDetectAllHandlerMappings(false);

    AnnotationConfigWebApplicationContext applicationContext = new
    AnnotationConfigWebApplicationContext();
    applicationContext.setParent(parentContext);

    applicationContext.register(Child2Configuration.class);

    applicationContext.refresh();

    dispatcherServlet.setApplicationContext(applicationContext);

    ServletRegistrationBean servletRegistrationBean = new
    ServletRegistrationBean(dispatcherServlet, true, "/child2/*");

    servletRegistrationBean.setName("child2");

    servletRegistrationBean.setLoadOnStartup(1);

    return servletRegistrationBean;
    }
    }
  • 关于spring-mvc - 如何在模块化 Spring Boot 应用程序中定义隔离的 Web 上下文?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37659608/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com