@ConditionalOnProperty 注解
@ConditionalOnProperty 注解详解
@ConditionalOnProperty 是 Spring Boot 的条件注解,用于根据配置文件中的属性值控制 Bean 是否被创建。它检查指定属性是否存在、值是否匹配,从而决定是否启用相关配置。(符合条件就创建Bean)
工作原理
- 检查逻辑:注解会检查配置文件(如
application.yaml或application.properties)中的属性值。 - 条件判断:
- 如果属性值(name| value) 等于
havingValue(或默认匹配),则条件为真,Bean 被创建。 - 否则为假,Bean 不被创建。
- 如果属性值(name| value) 等于
- 结果影响:
- 为真:Bean 被实例化,配置生效。
- 为假:Bean 被跳过,配置无效。
主要参数
| 参数 | 说明 | 默认值 |
|---|---|---|
name / value |
配置文件中的属性名(从 application.yml 读取) |
- |
havingValue |
期望的属性值,只有匹配时才创建 Bean | ""(空字符串,表示只要属性存在即可) |
matchIfMissing |
属性不存在时是否默认匹配(true = 创建,false = 不创建) |
false |
prefix |
属性名前缀,用于简化配置(如 prefix="app" + name="enabled" → app.enabled) |
"" |
参数组合示例:
// 场景1: 属性必须存在且值为 "true"
@ConditionalOnProperty(name = "feature.enabled", havingValue = "true")
// 配置: feature.enabled=true ✅ | feature.enabled=false ❌ | 不存在 ❌
// 场景2: 属性存在即可(值不限)
@ConditionalOnProperty(name = "feature.enabled")
// 配置: feature.enabled=true ✅ | feature.enabled=false ✅ | 不存在 ❌
// 场景3: 属性不存在时默认创建
@ConditionalOnProperty(name = "feature.enabled", matchIfMissing = true)
// 配置: feature.enabled=true ✅ | feature.enabled=false ❌ | 不存在 ✅
基础示例
假设 application.yaml 配置如下:
app:
logging:
enabled: true # 可改为 false 或删除测试
@Configuration
public class AppConfig {
@Bean
@ConditionalOnProperty(name = "app.logging.enabled", havingValue = "true")
public LoggingService loggingService() {
return new LoggingService();
}
}
// 如果 app.logging.enabled=true → LoggingService 被创建
// 如果为 false 或不存在 → 不创建
实际业务场景
场景1:短信服务降级开关
需求:生产环境关闭短信发送功能,或切换到模拟实现(避免扣费)。
配置文件 application.yml:
service:
sms:
enabled: false
mock: false # true 则使用模拟实现(不实际发送)
实现代码:
@Configuration
public class SmsConfig {
// 真实短信服务(阿里云/腾讯云)
@Bean
@ConditionalOnProperty(name = "service.sms.enabled", havingValue = "true", matchIfMissing = false)
public SmsService realSmsService() {
return new AliyunSmsService(); // 或 TencentSmsService
}
// 模拟短信服务(开发/测试用)
@Bean
@ConditionalOnProperty(name = "service.sms.enabled", havingValue = "false", matchIfMissing = true)
public SmsService mockSmsService() {
return new MockSmsService(); // 只打印日志,不发送
}
}
效果:
- 生产环境关闭
enabled→ 自动切换到模拟实现,避免意外扣费 - 开发/测试环境开启 → 真实发送
场景2:多数据源动态切换(读写分离)
需求:根据配置选择使用主库(写)或从库(读)的数据源。
配置文件:
datasource:
mode: master # master=主库 | slave=从库 | cluster=集群模式
实现代码:
@Configuration
public class DataSourceConfig {
// 主数据源(写库)
@Bean
@ConfigurationProperties(prefix = "spring.datasource.master")
@ConditionalOnProperty(name = "datasource.mode", havingValue = "master", matchIfMissing = true)
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
// 从数据源(读库)
@Bean
@ConfigurationProperties(prefix = "spring.datasource.slave")
@ConditionalOnProperty(name = "datasource.mode", havingValue = "slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
// 集群模式(负载均衡)
@Bean
@ConditionalOnProperty(name = "datasource.mode", havingValue = "cluster")
public DataSource clusterDataSource() {
return new ClusterDataSource(); // 自定义实现
}
}
效果:
- 开发环境使用
mode: master→ 单库开发 - 生产环境使用
mode: slave→ 读写分离 - 高并发场景使用
mode: cluster→ 多库负载均衡
场景3:功能灰度发布(新功能开关)
需求:新功能上线时先对部分用户开放,通过配置控制是否启用。
配置文件:
feature:
new-ui:
enabled: true # 是否启用新UI
whitelist: "user1,user2,admin" # 白名单用户
实现代码:
@Configuration
public class FeatureConfig {
// 新版UI服务
@Bean
@ConditionalOnProperty(name = "feature.new-ui.enabled", havingValue = "true")
public UiService newUiService() {
return new NewUiService();
}
// 旧版UI服务(降级方案)
@Bean
@ConditionalOnProperty(name = "feature.new-ui.enabled", havingValue = "false", matchIfMissing = true)
public UiService legacyUiService() {
return new LegacyUiService();
}
}
// 使用示例
@Service
public class UserService {
@Autowired
private UiService uiService; // 根据配置自动注入新旧实现
public String getHomePage(String userId) {
return uiService.renderHomePage(userId);
}
}
效果:
- 灰度期间
enabled: false→ 所有用户用旧版 - 逐步放开
enabled: true→ 部分用户用新版 - 出问题立即回滚 → 改为
false即可
常见问题
Q1: matchIfMissing 的使用场景?
- 设为
true:默认启用的功能(如开发环境默认开启日志) - 设为
false:需要显式配置才能启用(如生产环境的监控功能)
Q2: 与 @Value 注解的区别?
| 特性 | @ConditionalOnProperty |
@Value |
|---|---|---|
| 作用范围 | 类/方法级别(控制 Bean 创建) | 字段/参数/方法级别(注入值) |
| 决策时机 | 应用启动时(只判断一次) | 每次访问时(动态读取) |
| 典型场景 | 功能开关、数据源切换 | 配置参数注入 |
Q3: 如何实现多条件组合?
使用 @ConditionalOnExpression(SpEL 表达式):
@ConditionalOnExpression("'${service.sms.enabled}' == 'true' and '${service.sms.mock}' == 'false'")
public SmsService realSmsService() { ... }