鉴于Spring Boot应用程序由一个引导程序模块和两个或多个独立的业务模块组成 - 每个模块都公开了特定于业务域的REST API,并且每个模块都使用独立的,独立的文档存储来实现数据持久性,如何配置这样的应用程序:
为了隔离各个业务模块的上下文(允许我在每个模块中管理独立的存储库配置),我尝试使用SpringApplicationBuilder中提供的上下文层次结构来隔离每个业务模块的上下文: / p>
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容器,每个容器都尝试绑定到同一个端口:
@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项目来说明这一点:
答案 0 :(得分:0)
为业务模块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会将上下文注入@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;
}
}