在 Spring Boot 的魔法书里,@ConditionalOnMissingBean 可能是最能体现“大度”的注解了。它的核心逻辑非常简单:“如果你没准备,那我就亲自动手;如果你已经准备了,我就靠边站。”
它是实现 Spring Boot 自动配置(Auto-configuration) 的基石。
1. 为什么要用它?
当你编写一个 Library(库)或 Starter 给别人用时,你通常会提供一个默认的 Bean 实现。但你又不想“独断专行”,万一用户想用自己定义的 Bean 替代你的默认实现呢?
如果没有这个注解,Spring 容器会因为发现两个同类型的 Bean 而抛出 NoUniqueBeanDefinitionException。有了它,用户定义的 Bean 永远拥有最高优先权。
2. 基本语法
你可以把它标注在 @Bean 方法上,或者直接标注在类上。
@Configuration
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean(Service.class)
public Service defaultService() {
return new DefaultServiceImpl();
}
}
常用属性:
value / type: 检查容器中是否存在指定类型的 Bean(最常用)。
name: 检查容器中是否存在指定名称的 Bean。
annotation: 检查是否有 Bean 被标注了某个特定的注解。
3. 实战案例:自定义短信发送器
假设你写了一个短信插件,默认使用阿里云,但允许用户自定义。
第一步:定义接口
Java
public interface SmsSender {
void send(String message);
}
第二步:自动配置类
@Configuration
public class SmsAutoConfiguration {
@Bean
@ConditionalOnMissingBean(SmsSender.class) // 如果用户没定义 SmsSender,执行这个方法
public SmsSender aliyunSmsSender() {
System.out.println("检测到未定义 SmsSender,加载默认阿里云实现...");
return new AliyunSmsSender();
}
}
第三步:用户自定义(可选)
如果用户在自己的代码里写了下面这段,上面的 aliyunSmsSender 就会自动失效:
@Component
public class MyTencentSmsSender implements SmsSender {
@Override
public void send(String message) {
System.out.println("使用腾讯云发送短信...");
}
}
4. 避坑指南(非常重要!)
在使用这个注解时,最容易犯的错误就是加载顺序问题。
金律: Spring 必须先扫描到“用户自定义的 Bean”,然后才能判断出“是否缺失”。
放在自动配置类中: 这种注解通常用在
src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports声明的配置类里。Spring Boot 会保证先加载用户的@Component,再加载这些自动配置。避免在同一个配置类内竞争: 如果你在同一个
@Configuration类里写了两个同类型的 Bean,且都加了该注解,结果可能取决于方法的声明顺序,这通常不是你想要的。
评论