为何@ConditionalOnBean(RedisTemplate.class)不生效,@ConditionalOnMissingBean却生效?
为什么@ConditionalOnBean和@ConditionalOnMissingBean的表现与预期相反?
我有一个依赖RedisTemplate的FlowControlConfig配置类:
- 使用
@ConditionalOnBean(RedisTemplate.class)时,配置类不生效,FlowControlCache无法实例化,但调试确认RedisTemplate已经完成实例化。 - 换成
@ConditionalOnMissingBean(RedisTemplate.class)时,配置类反而正常工作,且注入的RedisTemplate不为null。
相关代码如下:
RedisTemplate的Bean定义
// RedisTemplate instance @Bean @SuppressWarnings("all") public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); template.setKeySerializer(stringRedisSerializer); template.setHashKeySerializer(stringRedisSerializer); template.setValueSerializer(jackson2JsonRedisSerializer); template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; }
使用@ConditionalOnBean的配置类
@Configuration @ConditionalOnBean(RedisTemplate.class) public class FlowControlConfig { @Bean public FlowControlCache flowControlCache(RedisTemplate redisTemplate) { return new FlowControlCache() { @Override public void save(String key, Integer value, Long time, TimeUnit timeUnit) { redisTemplate.opsForValue().set(key, value, time, timeUnit); } @Override public void save(String key, Integer value) { redisTemplate.opsForValue().set(key, value); } @Override public Integer get(String key) { return (Integer) redisTemplate.opsForValue().get(key); } }; } }
换成@ConditionalOnMissingBean的配置类
@Configuration @ConditionalOnMissingBean(RedisTemplate.class) public class FlowControlConfig { @Bean public FlowControlCache flowControlCache(RedisTemplate redisTemplate) { return new FlowControlCache() { @Override public void save(String key, Integer value, Long time, TimeUnit timeUnit) { redisTemplate.opsForValue().set(key, value, time, timeUnit); } @Override public void save(String key, Integer value) { redisTemplate.opsForValue().set(key, value); } @Override public Integer get(String key) { return (Integer) redisTemplate.opsForValue().get(key); } }; } }
核心原因:Spring条件判断时机与配置类加载顺序
- @ConditionalOnBean的判断逻辑:Spring处理配置类时,会先解析类上的条件注解。如果
RedisTemplate所在的配置类还未被执行(Bean未注册到容器),此时容器中不存在RedisTemplate类型的Bean,@ConditionalOnBean(RedisTemplate.class)条件不满足,FlowControlConfig不会被加载。 - @ConditionalOnMissingBean的生效逻辑:判断条件时
RedisTemplate确实未注册,条件满足,FlowControlConfig被加载;后续Spring处理RedisTemplate的配置类,完成Bean实例化与注册,此时flowControlCache方法注入依赖时,容器中已经存在RedisTemplate实例,因此能正常创建FlowControlCache。 - 泛型匹配的潜在影响:你的
RedisTemplate是带泛型的RedisTemplate<String, Object>,而@ConditionalOnBean(RedisTemplate.class)按原始类型判断,这可能加剧类型匹配问题,但核心矛盾仍是加载顺序。
解决方法
方法1:指定配置类加载顺序
在Spring Boot环境下,使用@AutoConfigureAfter让FlowControlConfig在Redis相关配置类之后加载:
@Configuration @ConditionalOnBean(RedisTemplate.class) @AutoConfigureAfter(RedisAutoConfiguration.class) // 自定义Redis配置类则替换为对应类名 public class FlowControlConfig { // 原有代码 }
纯Spring环境可使用@DependsOn指定依赖的Bean名称:
@Configuration @ConditionalOnBean(RedisTemplate.class) @DependsOn("redisTemplate") public class FlowControlConfig { // 原有代码 }
方法2:指定Bean名称进行条件判断
在@ConditionalOnBean中明确指定RedisTemplate的Bean名称(默认是方法名redisTemplate),避免类型匹配问题:
@Configuration @ConditionalOnBean(name = "redisTemplate") public class FlowControlConfig { // 原有代码 }
方法3:合并配置类
将RedisTemplate的Bean定义与FlowControlConfig放在同一个配置类中,确保RedisTemplate先被实例化:
@Configuration public class RedisAndFlowControlConfig { @Bean @SuppressWarnings("all") public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { // 原有RedisTemplate代码 } @Bean public FlowControlCache flowControlCache(RedisTemplate<String, Object> redisTemplate) { // 原有FlowControlCache代码 } }
内容的提问来源于stack exchange,提问作者Riling Li
相关产品推荐
相关产品推荐

