为何满足条件时@ConditionalOnBean仍不匹配?
问题
我首次尝试为SpringBoot应用开发带自动配置的库,配置入口类代码如下(部分内容已删减):
@AutoConfigurationPackage @AutoConfigureAfter({RestTemplateAutoConfiguration.class, JacksonAutoConfiguration.class}) @AutoConfigureBefore({org.zalando.logbook.autoconfigure.LogbookAutoConfiguration.class}) @ConditionalOnWebApplication @EnableConfigurationProperties({...}) @Configuration(...) @ConditionalOnBean(ObjectMapper.class) public class MyAutoConfiguration {
该配置在一个项目中正常工作,但在另一个项目中失败。从调试日志可见,ObjectMapper Bean在MyAutoConfiguration之前创建,但仍未通过条件校验。
日志显示:
///line ~800 JacksonAutoConfiguration.JacksonObjectMapperConfiguration#jacksonObjectMapper matched: - @ConditionalOnMissingBean (types: com.fasterxml.jackson.databind.ObjectMapper; SearchStrategy: all) did not find any beans (OnBeanCondition) ////line ~2080 ........redacted.MyAutoConfiguration: Did not match: - @ConditionalOnBean (types: com.fasterxml.jackson.databind.ObjectMapper; SearchStrategy: all) did not find any beans of type com.fasterxml.jackson.databind.ObjectMapper (OnBeanCondition) Matched: - @ConditionalOnWebApplication (required) found 'session' scope (OnWebApplicationCondition)
已确认库和运行时版本一致,为何条件满足但校验失败?
原因分析与解决方案
核心原因:类加载器隔离导致类型不匹配
即使ObjectMapper的全限定类名相同,只要两个项目中该类由不同类加载器加载,Spring就会判定为不同类型,@ConditionalOnBean自然找不到匹配的Bean。
具体解决办法
排查依赖树,消除重复依赖
失败项目可能通过不同引入路径加载了多套Jackson类库,导致类加载器隔离。执行以下命令检查依赖:mvn dependency:tree # Maven项目 ./gradlew dependencies # Gradle项目找到重复的Jackson依赖,通过
<exclusions>(Maven)或exclude(Gradle)排除冗余依赖,确保项目中只有一套Jackson类文件。调整条件注解的搜索策略
默认的SearchStrategy.ALL会跨上下文搜索,可能受到类加载器影响。改为SearchStrategy.CURRENT缩小搜索范围到当前配置的上下文:@ConditionalOnBean(type = "com.fasterxml.jackson.databind.ObjectMapper", search = SearchStrategy.CURRENT)替换条件注解,降低校验复杂度
用@ConditionalOnClass(ObjectMapper.class)替代@ConditionalOnBean,先确保类存在,再通过@Autowired注入ObjectMapper。这种方式不依赖Bean的创建时机,能规避类加载器带来的类型判定问题:@ConditionalOnClass(ObjectMapper.class) // 移除@ConditionalOnBean public class MyAutoConfiguration { @Autowired private ObjectMapper objectMapper; // ... }检查自定义ObjectMapper的类型
如果失败项目中有自定义ObjectMapper的@Bean配置,确认其类型是com.fasterxml.jackson.databind.ObjectMapper本身,而非子类或CGLIB代理类——代理类会被Spring判定为不同类型,导致@ConditionalOnBean不匹配。
内容的提问来源于stack exchange,提问作者Antoniossss

