前情提要
前面探讨了management端口开启,grpc端口开启,本文继续探讨在SpringApplication中开启多个端口的方式之多ApplicationContext, 相比management端口基于多WebServer实例, 多ApplicationContext的颗粒度更大,也会略显粗暴,优点是简单。
一、思路概要
在一个JVM进程中创建两个ApplicationContext各自玩自己的,互不影响,只要两个ApplicationContext share基础的SpringBoot库即可,最终效果大约是下面这个样子。
二、具体实现
首先建议以Config对象组织来组织各自的上下文, 一方面可以自定义预期上下文包含的类,以及必要的自定义配置。例子如下
@SpringBootApplication(scanBasePackageClasses = {})
public class ViewContextConfig {
@Bean
public xxx newBeanInstance(){
return xxx;
}
}
其次,在某个入口函数处基于两个Config对象构造ApplicationContext
@Slf4j
public class ApplicationStarter {
public static void main(String[] args) {
ConfigurableApplicationContext first = SpringApplication.run(ViewContextConfig1.class, args);
log.info("ApplicationContext1 started");
ConfigurableApplicationContext second = SpringApplication.run(ViewContextConfig2.class, args);
log.info("ApplicationContext2 started");
}
}
三、其他问题
很多事情,原理可能无比简单,但能在工程中落地就是另外一个问题。今天的思路也是一样。接下来聊聊个人遇到的问题。比如父子关系,和部分对象依赖。
父子关系
伟大的Spring框架提供了这么个功能,childContext.setParent(parentContext); 在ApplicationContext初始化之前调用,childContext会在依赖注入时将parentContext中的对象作为候选项。
子容器结束,父容器不受影响。但父容器结束,子容器也会一并结束。
部分依赖
父子容器的声明周期,意味着子容器可以在父容器初始化之后,依赖其中的对象,但不构建父子关系。在子容器初始化完成后,再构造父子关系,从而解决部分依赖和生命周期问题。样例如下:
@Slf4j
public class ApplicationStarter {
public static void main(String[] args) {
ConfigurableApplicationContext parent = SpringApplication.run(ViewContextConfig1.class, args);
log.info("ApplicationContext1 started");
SpringApplication subApp = new SpringApplication(ViewContextConfig2.class);
subApp.addInitializers((ctx) -> {
ConfigurableListableBeanFactory beanFactory = ctx.getBeanFactory();
beanFactory.registerSingleton(“beanName”, parent.getBean(XX.class));
});
ConfigurableApplicationContext child = subApp.run("--spring.profiles.active=XX");
child.setParent(parent);
log.info("ApplicationContext2 started");
}
}
回过头来,以上问题的解决方案,可以在扫描解决,差别就是会创建多个对象,并且两者完全解耦合。此处,仅做解决方式的探讨。
总结
本文介绍了SpringBoot下基于多个ApplicationContext开启多端口,并介绍了父子容器的声明周期和依赖关系问题,为读者解决问题提供参考,感谢你的阅读。