如何在Spring项目中获取其他独立项目的ApplicationContext
跨独立Spring项目获取ApplicationContext实现方案
以下方案均适配标准HotSpot虚拟机,不需要修改原有依赖Jar,不需要做字节码增强新增类字段/方法。
按部署场景选择对应实现
场景1:两个项目运行在同一个JVM进程内(如同Tomcat容器下多Web应用、同进程启动多个Spring容器)
这种场景不需要跨进程通信,通过共享类路径下的静态持有类即可实现,步骤如下:
- 将如下工具类放在两个项目共同的上层共享类路径下(比如Tomcat的lib目录、进程级公共依赖目录),不要放在任意一个项目的私有类加载路径中,避免类加载器隔离导致静态变量不互通:
import org.springframework.context.ApplicationContext; public class SharedAppContextHolder { private static volatile ApplicationContext targetContext; public static void bind(ApplicationContext ctx) { targetContext = ctx; } public static ApplicationContext get() { return targetContext; } }
- 在被获取上下文的Spring项目中,注册一个容器回调,在容器启动完成后将自身ApplicationContext绑定到上述持有类中。如果无法修改该项目的代码和原有Jar,可以通过Java Agent的
premain方法在启动时注入该回调逻辑;如果可以给项目增加配置类,直接注册如下Bean即可:
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ContextBindConfig { @Bean public BeanFactoryPostProcessor bindContextPostProcessor() { return beanFactory -> { if (beanFactory instanceof ApplicationContext ctx) { SharedAppContextHolder.bind(ctx); } }; } }
- 在需要获取上下文的项目中,直接调用
SharedAppContextHolder.get()即可拿到目标项目的ApplicationContext实例。
注意:如果存在类加载器隔离机制,必须保证
SharedAppContextHolder由公共上层类加载器加载,否则两个项目加载到的Holder类是不同的类,静态变量无法共享。
场景2:两个项目是独立JVM进程部署(跨进程)
跨JVM场景下不存在直接获取另一个JVM堆内存中对象引用的可能,不需要尝试JNI、直接对象暴露这类方案,通过间接通信的方式实现即可:
- 方案1:自定义JMX MBean实现访问。不要直接暴露ApplicationContext实例(该类内部持有大量不可序列化、类加载隔离的依赖,默认无法通过JMX传递),而是在被访问项目中定义标准MBean,封装需要的ApplicationContext操作能力(比如按名称/类型获取Bean、调用Bean方法等),调用方通过JMX连接到目标进程后调用MBean方法,间接操作目标上下文。
- 方案2:注入轻量通信端点。如果无法修改被访问项目的代码,可以通过Java Agent在目标项目启动时注册Spring容器监听器,等容器启动完成拿到ApplicationContext后,绑定一个轻量HTTP/RMI端点,调用方通过网络请求访问端点即可操作目标上下文。
之前尝试方案的问题说明
- ASM增强
SpringApplication新增字段/方法:标准HotSpot虚拟机的类重定义机制不允许运行时修改类结构(新增字段、方法、父类等),仅DCEVM这类定制虚拟机支持该特性,普通生产环境不需要走这个方向。 - 修改Jar包实现:上述方案完全不需要侵入原有依赖Jar,没有必要走修改Jar的重打包路线。
- JMX直接暴露ApplicationContext:JMX本身支持传递对象,但ApplicationContext属于复杂容器对象,内部依赖大量未实现序列化、且受类加载器隔离的组件,直接传递必然失败,属于用法问题而非JMX能力问题。
- JNI方案:JNI仅能操作当前进程JVM的内存对象,跨进程场景下完全无法访问其他JVM的堆内存,同进程场景下也不需要用JNI做上下文传递。
内容的提问来源于stack exchange,提问作者ght ggg
相关产品推荐
相关产品推荐

