SpringBoot22-@Conditional条件装配
一、解释@Conditional
@Conditional的作用是:只有在满足某个条件时,才把这个 Bean 放进 Spring 容器里。
不满足条件 → 不装配
满足条件 → 才装配
你可以理解为:
if (条件满足) { 把这个 Bean 交给 Spring 管理 } else { 不要管它 }1、例子
你有一个 Bean:
@Bean public UserService userService() { return new UserService(); }现在你想让这个 Bean只有在某个条件成立时才生效。
加@Conditional
@Bean @Conditional(MyCondition.class) // ✅ 在某个条件成立时,才注册 public UserService userService() { return new UserService(); }MyCondition是你写的“判定逻辑”类:
public class MyCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 返回 true:装配 // 返回 false:不装配 return true; // 你可以加自己的判断逻辑 } }2、这在什么时候特别有用?
| 场景 | 示例 | 说明 |
|---|---|---|
| 根据系统环境选择 Bean | Windows vs Linux | Windows 用 A Bean,Linux 用 B Bean |
| 根据配置文件开关启用功能 | my.feature.enabled=true | 开关功能模块 |
| 判断类是否存在 | Class.forName(...) | 例如自动配置第三方库时 |
| 根据是否存在某个 Bean | 条件注入 | 避免重复装配、冲突 |
二、现成的条件注解
Spring Boot 已经提供了很多现成的条件注解(不用自己写Condition)
| 注解 | 意义 | 示例 |
|---|---|---|
@ConditionalOnClass | 某个类存在才装配 | 缓存模块依赖 Redis 才启动 |
@ConditionalOnMissingClass | 某个类不存在才装配 | 防止重复 |
@ConditionalOnBean | 容器里存在某 Bean 才装配 | 依赖链 |
@ConditionalOnMissingBean | 容器里没有某 Bean 才装配 | 自动配置常用 |
@ConditionalOnProperty | 根据配置文件值决定装配 | 功能开关 |
2-1、最常用:@ConditionalOnProperty(做配置开关)
application.yml:
my.feature.enabled: true配置类:
@Bean @ConditionalOnProperty(name="my.feature.enabled", havingValue="true") public UserService userService() { return new UserService(); }改成
false→ 这个 Bean 自动消失
不用改代码,只改配置,非常优雅
2-2、Spring Boot 自动配置为什么强?
因为用了大量@Conditional
Spring Boot 的自动配置 ≈ @Import(...) + 一堆 @ConditionalXxx
比如 Redis 自动配置:
@Configuration @ConditionalOnClass(RedisConnection.class) // 项目里有 Redis 依赖才生效 class RedisAutoConfiguration { }如果你没引入 Redis 依赖 → 这整个配置类直接跳过。
这就是为什么:
“你引什么依赖,就自动开什么功能。”
小结:
@Conditional = 带条件的 @Bean
满足才装,不满足就跳过
Spring Boot 自动配置全靠它
三、@Conditional 注解添加在哪里
@Conditional不是随便加的,要加在“Spring 解析 Bean 的地方”。
@Conditional可以加在:
配置类上@Configuration(控制整个配置类是否生效)
@Bean方法上(控制某个 Bean 是否生效)
其它地方不要加,它不会生效。
1)加在配置类上(控制一坨 Bean)
@Configuration @Conditional(MyCondition.class) // ✅ 满足条件时,这里所有 Bean 才会被注册 public class AppConfig { @Bean public UserService userService(){ return new UserService(); } @Bean public OrderService orderService(){ return new OrderService(); } }结果:
如果条件成立 →
UserService和OrderService都进入容器如果条件不成立 →这个配置类整个不生效
适用于:开关整个功能模块
2)加在@Bean方法上(控制单个 Bean)
@Configuration public class AppConfig { @Bean @Conditional(MyCondition.class) // ✅ 只有满足条件才创建这个 Bean public UserService userService(){ return new UserService(); } }结果:
满足条件 →
userService注册不满足 → 不注册(也就不能
@Autowired)
适用于:只控制某个特定 Bean 是否装配
总结:
@Conditional 要么加在配置类 @Configuration上,要么加在@Bean 方法上。
- 控制模块级 → 配置类上
- 控制单个 bean → 方法上
四、举例讲解:@ConditionalOnBean、@ConditionalOnMissingBean
4-1、它们俩的本质区别
| 注解 | 含义 | 什么时候装配? |
|---|---|---|
@ConditionalOnBean | 当容器中已经有某个 Bean 时才装配 | 依赖存在时才生效 |
@ConditionalOnMissingBean | 当容器中没有某个 Bean 时才装配 | 避免重复Bean / 提供默认实现 |
你可以理解为:
ConditionalOnBean = 有就装 ConditionalOnMissingBean = 没有才装4-2.@ConditionalOnBean示例(“有依赖才启用”)
假设:
只有你项目里已经有 UserService
才允许使用 OrderService
@Configuration public class AppConfig { @Bean public UserService userService() { return new UserService(); } @Bean @ConditionalOnBean(UserService.class) // ✅ 如果容器里存在 UserService 才创建 public OrderService orderService() { return new OrderService(); } }结果:
| 是否存在 UserService | OrderService 是否会注册? |
|---|---|
| 存在 ✅ | ✅ 会装配 |
| 不存在 ❌ | ❌ 不装配 |
适用场景:
比如一个功能必须依赖另一个模块才能开启。
4-3.@ConditionalOnMissingBean示例(“没有才给你默认实现”)
Spring Boot 在自动配置里用得特别多。
比如,给你一个默认的UserService,但如果你自己已经写了,就不用它的:
@Configuration public class AppConfig { // ✅ 默认 UserService @Bean @ConditionalOnMissingBean(UserService.class) public UserService defaultUserService(){ return new UserService("默认实现"); } }用户自己写了一个:
@Service public class UserService { public UserService() { System.out.println("这是我自己的实现"); } }结果:
Spring Boot 发现你自己已经实现了
UserService它自动跳过默认的那一个
| 是否存在用户自定义 UserService | 默认实现是否会装配? |
|---|---|
| 存在 ✅ | ❌ 跳过默认实现 |
| 不存在 ❌ | ✅ 使用默认实现 |
4-4、为什么 Spring Boot 自动配置很聪明?
因为它常常写:
@Bean @ConditionalOnMissingBean public Xxx defaultXxx(){ ... }你不写,就给你默认的
你一旦写了,直接用你的
这就解释了大家常说的:
Spring Boot 自动配置 → "约定优于配置""自动装配"是机制,"约定优于配置"是设计思想。它们合在一起,解决的是"重复写样板配置"的问题。
"约定"就是:框架先帮你把默认答案填好
"约定"的本质是:框架预设了一套"最常用"的默认行为。
| 场景 | 约定(默认值) | 你的选择 |
|---|---|---|
你引入了spring-boot-starter-web | 约定你要用 Tomcat,端口 8080 | 不需要写任何配置就能启动 |
你引入了mysql-connector-java | 约定你要连 MySQL | 只需要填 url/username/password |
你引入了spring-boot-starter-data-redis | 约定 Redis 在 localhost:6379 | 不改配置就能连本地 Redis |
| 静态资源放哪 | 约定放在classpath:/static/ | 直接丢文件进去,不用配路径 |
"优于配置"的意思是:约定好的默认值,优先级高于你手动写的配置。只有当默认值不符合你的需求时,你才需要去覆盖它。
Spring Boot 用了一系列@Conditional注解来实现"约定判断":
Table
| 注解 | 含义 | 约定的体现 |
|---|---|---|
@ConditionalOnClass | classpath 里有某个类才生效 | 你引入了某个依赖,我就认为你要用某个功能 |
@ConditionalOnMissingBean | 容器里没有这个 Bean 才生效 | 你自己配了,我就不插手 |
@ConditionalOnProperty | 某个配置属性存在才生效 | 你显式开启了这个功能 |
@ConditionalOnWebApplication | 是 Web 应用才生效 | 你引入了 web starter,我就按 Web 应用来配 |
这就是"约定"的技术实现:框架通过检查你的环境(classpath、配置、Bean 是否存在),来"猜测"你需要什么,然后自动配置。
一句话:
Spring Boot 的自动装配,就是框架根据"你引入了什么依赖"这个约定,自动帮你把最可能需要的配置做完,让你尽量少写甚至不写配置代码。
总结
@ConditionalOnBean → 有它才配我 @ConditionalOnMissingBean → 你没写我来补前者做依赖判断(依赖存在才装配)
后者做默认兜底(避免 Bean 冲突)