如何基于Spring Java配置动态加载启动后加入classpath的jar中Bean?
问题原因分析
- 你调用
refresh()方法的操作是问题核心:Spring应用上下文的refresh()是初始化上下文的全生命周期方法,已经完成初始化的上下文重复调用该方法时,会先销毁所有已创建的Bean(包括内置Web服务器、已注册的接口、业务Bean等),再重新走初始化流程,所以会直接停掉你正在运行的Web应用。
可行解决方案
不需要调用全量refresh(),只需要触发配置类的解析和新Bean的注册流程即可,示例代码如下:
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.ConfigurationClassPostProcessor; // 加载外部Jar中的配置类,注意类的全限定名要和实际配置类一致 Class<?> confClass = jarService.loadClass("com.transportexchangegroup.testConf.AppConf"); BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory(); // 1. 注册配置类的BeanDefinition AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(confClass); registry.registerBeanDefinition(confClass.getSimpleName(), configBeanDef); // 2. 利用Spring自带的配置类处理器解析配置,自动处理@ComponentScan、@Bean等注解,完成所有相关Bean的定义注册 ConfigurationClassPostProcessor configProcessor = applicationContext.getBean(ConfigurationClassPostProcessor.class); configProcessor.postProcessBeanDefinitionRegistry(registry); // 3. 实例化所有新注册的非懒加载Bean applicationContext.getAutowireCapableBeanFactory().preInstantiateSingletons();
注意事项
- 加载外部Jar的类加载器需要以当前Spring上下文的类加载器为父加载器,避免出现类隔离导致的类转换异常。
- 如果配置类依赖上下文已有的Bean,不需要额外处理,解析过程中会自动完成依赖注入。
RestController加载说明
上述方案可以正常加载Jar包中的@RestController:配置类的@ComponentScan会扫描到Controller类并完成Bean注册,Spring MVC默认的RequestMappingHandlerMapping会自动检测到新注册的Controller,自动完成接口路径的映射,不需要额外配置即可正常访问接口。
内容的提问来源于stack exchange,提问作者Arthur
相关产品推荐
相关产品推荐

