通俗易懂!Spring 条件化装配 @Conditional 全家福(2025 面试+实战必备,背完直接起飞)
一图看懂 Spring 条件装配全体系(面试画图神器)
@Conditional(爷爷,Spring 4.0 出生)
├── @Profile → 根据环境(dev/test/prod)切换
├── @ConditionalOnProperty → yml 配置开关(最最最常用!)
├── @ConditionalOnBean → 容器里有没有某个 Bean
├── @ConditionalOnMissingBean→ 容器里没有某个 Bean 才装配(神器!)
├── @ConditionalOnClass → 类路径下有没有某个 class
├── @ConditionalOnMissingClass→ 没有某个 class 才装配
├── @ConditionalOnExpression → SpEL 表达式随便写
├── @ConditionalOnJava → JDK 版本判断
├── @ConditionalOnResource → 有没有某个资源文件
├── @ConditionalOnCloudPlatform → 是不是在云上运行
├── @ConditionalOnWebApplication → 是不是 Web 项目
├── @ConditionalOnNotWebApplication → 不是 Web 项目
└── @ConditionalOnSingleCandidate → 同类型只有一个 Bean
2025 年真实项目最常用的 5 个(90%场景就这几个)
| 排名 | 注解 | 真实用法示例(直接抄) | 实际场景占比 |
|---|---|---|---|
| 1 | @ConditionalOnProperty | “`java | |
| @Bean | |||
| @ConditionalOnProperty(name = “feature.pay.enabled”, havingValue = “true”, matchIfMissing = false) | |||
| public AliPayService aliPay() { return new AliPayService(); } | |||
| “` | 50% | ||
| 2 | @ConditionalOnMissingBean | “`java | |
| @ConditionalOnMissingBean(RedisTemplate.class) | |||
| @Bean | |||
| public RedisTemplate redisTemplate(…) { … } | |||
| “` | 25% | ||
| 3 | @Profile | “`java | |
| @Profile(“dev”) | |||
| @Configuration | |||
| public class DevConfig { … } | |||
| “` | 15% | ||
| 4 | @ConditionalOnClass | “`java | |
| @ConditionalOnClass(name = “com.zaxxer.hikari.HikariDataSource”) | |||
| @Bean | |||
| public HikariDataSource dataSource() { … } | |||
| “` | 8% | ||
| 5 | @ConditionalOnExpression | “`java | |
| @ConditionalOnExpression(“${server.port} == 8080 or ${server.port} == 8081”) | |||
| “` | 2% |
实战最强组合写法(大厂标配,直接抄进项目)
// 1. 开发环境用 H2 数据库,生产用 MySQL
@Profile("dev")
@Bean
public DataSource h2DataSource() { ... }
@Profile("!dev")
@Bean
public DataSource mysqlDataSource() { ... }
// 2. 只有配置了 redis.enabled=true 才装配 RedisTemplate
@Bean
@ConditionalOnProperty(prefix = "spring.redis", name = "enabled", havingValue = "true")
public RedisTemplate<String, Object> redisTemplate(...) { ... }
// 3. 项目没自己配 DataSource 才用 Spring Boot 的默认 Hikari
@Configuration
@ConditionalOnMissingBean(DataSource.class)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfig { ... }
// 4. 只有类路径有 Kafka,才装配 KafkaTemplate
@ConditionalOnClass(KafkaTemplate.class)
@EnableKafka
@Configuration
public class KafkaAutoConfig { ... }
// 5. 生产环境才开启 Redisson 分布式锁
@Bean
@ConditionalOnProperty(name = "lock.type", havingValue = "redisson")
@Profile("prod")
public RedissonClient redissonClient() { ... }
面试终极 6 连问 + 标准答案(背完无敌)
- @ConditionalOnProperty 怎么写才最安全?
答:三个参数全写!
@ConditionalOnProperty(
name = "feature.xxx.enabled",
havingValue = "true",
matchIfMissing = false // 没配时不生效
)
- @ConditionalOnMissingBean 是怎么工作的?
答:Spring Boot 所有自动装配都靠它!它让用户可以轻松覆盖默认配置。 - @Profile 和 @ConditionalOnProperty 什么关系?
答:@Profile 底层就是 @ConditionalOnProperty,@Profile("dev")等价于@ConditionalOnProperty(name="spring.profiles.active", havingValue="dev") - 我想在本地开发时用假支付,线上用真支付,怎么写?
答:
@Bean
@Profile("dev")
public PayService fakePay() { return new FakePayService(); }
@Bean
@Profile("!dev")
public PayService realPay() { return new AliPayService(); }
- Spring Boot 是怎么实现“开箱即用又能自定义”的?
答:全靠 @ConditionalOnMissingBean + @ConditionalOnClass 组合拳! - @Conditional 家族的执行顺序?
答:在 BeanDefinition 注册完、实例化之前执行(比 @PostConstruct 早得多)。
终极记忆口诀(10 秒记住全部)
“有配置 OnProperty,没 Bean OnMissingBean,
有类 OnClass,没类 OnMissingClass,
开发用 Profile,复杂写 Expression,
Spring Boot 全靠 MissingBean 实现自动装配!”
背完这张图 + 5个最常用写法 + 口诀,
面试官问“Spring 条件装配怎么玩”,你直接甩代码 + 画图,
他当场就能给你发 offer!冲!