Spring Boot升级至2.2.0.RELEASE后启动失败、Bean未加载问题排查
问题根因
该故障由Spring Boot 2.2.0默认集成的Spring Framework 5.2 配置类解析逻辑变更触发,核心触发逻辑如下:
- 自定义配置类
EKMSClientSdkConfiguration继承了来自第三方Jar的抽象类ClientConfiguration,该父类未标注任何Spring配置注解,且内部定义了@Bean方法,其中restClient()直接调用了同类的apiClient()方法 - Spring 5.2之前,
@Configuration默认的Full代理模式(proxyBeanMethods = true)会自动为这类无注解的抽象父类生成CGLIB代理,正确处理类内部@Bean方法的调用逻辑,配置类可以正常注册。5.2版本新增了配置类合法性校验:如果配置类的父类是未标注Spring配置注解的抽象类,框架无法为其生成符合要求的CGLIB代理,会直接跳过整个配置类的解析流程,类上的@ComponentScan、条件注解、类内的@Bean方法、@PostConstruct生命周期方法全部不会生效,直接出现安全提供者未注册、关联Bean未创建、启动失败的现象。
排查步骤
- 启动应用时在配置文件中添加
debug=true,查看配置类评估报告,会看到EKMSClientSdkConfiguration被标记为跳过状态,跳过原因多为配置类无法生成代理子类 - 查看启动日志的WARN级别日志,会看到5.2版本新增的配置类代理风险提示,明确指向抽象父类的
@Bean方法无法被正确拦截 - 临时将
@Configuration注解修改为@Configuration(proxyBeanMethods = false)切换为Lite配置模式重启,如果配置类可以正常加载,即可确认根因判断正确。
解决方案
按改造成本和长期稳定性从高到低选择:
- 推荐方案:移除对第三方抽象配置类的继承
不需要依赖第三方的抽象类结构,直接把父类中定义的restClient()、apiClient()两个@Bean方法复制到自定义配置类中,删除继承关系,从根源上规避代理逻辑兼容问题,后续升级Spring版本也不会出现同类问题。改造后的配置类示例:@Configuration @Slf4j @ComponentScan(basePackages = "com.xxx.yyy.ekms.sdk") @ConditionalOnProperty(name = "ekms.enabled", havingValue = "true") public class EKMSClientSdkConfiguration { @PostConstruct public void addSecurityProvider() { Security.addProvider(new BouncyCastleFipsProvider()); } @Bean public ApiClientBuilder apiClientBuilder() { return new DefaultApiClientBuilder(); } @Bean public EKMSClient restClient() { return new EKMSRestClientImpl(this.apiClient()); } @Bean public ApiClient apiClient() { return Configuration.getDefaultApiClient(); } } - 快速兼容方案:关闭配置类的Bean方法代理
如果暂时不想调整代码结构,直接在自定义配置类的@Configuration注解中添加proxyBeanMethods = false参数,切换为Lite配置模式。该模式下Spring不会为配置类生成CGLIB代理,自然不会触发抽象父类的代理校验逻辑,配置类可以正常加载。注意:Lite模式下类内部
@Bean方法互相调用不会走Spring容器的Bean获取逻辑,会直接执行本地方法。当前场景中apiClient()方法本身是直接返回静态默认客户端实例,没有依赖其他Spring Bean的逻辑,所以不会出现Bean重复创建或者依赖注入失败的问题。
注解修改示例:@Configuration(proxyBeanMethods = false) @Slf4j @ComponentScan(basePackages = "com.xxx.yyy.ekms.sdk") @ConditionalOnProperty(name = "ekms.enabled", havingValue = "true") public class EKMSClientSdkConfiguration extends ClientConfiguration { // 原有业务代码无需修改 } - 兜底方案:显式注册核心Bean
如果以上两种方案都不适用,可以直接在启动类或者其他通用配置类中通过@Bean方法显式注册BouncyCastleFipsProvider、ApiClient、EKMSClient等核心Bean,绕过配置类扫描解析的流程,不过这种方式维护成本较高,只建议临时应急使用。
内容的提问来源于stack exchange,提问作者Amrita Sah
相关产品推荐
相关产品推荐

