Spring Boot 条件装配机制:用它写出更优雅的自动配置
在使用 Spring Boot 开发企业项目或中台框架时,我们经常会遇到这样的需求:
- 如果用户没有手动配置 Bean,就提供默认实现;
- 如果某个功能配置项为 true,才启用该功能;
- 如果引入了某个三方依赖,才自动配置其支持。
这些背后的逻辑,靠的就是 Spring Boot 的条件装配机制(Conditional Auto Configuration)。
本文就带你了解一下条件装配的核心注解和使用方法。
什么是条件装配?
条件装配是一种基于“是否满足某些条件”来决定 Bean 是否注册到 Spring 容器的机制。
通过条件装配,我们可以让框架或模块根据环境动态控制哪些 Bean 被注入,实现高度的灵活性、可插拔性。
常见的条件装配注解
注解 | 作用 | 场景示例 |
---|---|---|
@ConditionalOnMissingBean | 当 Spring 中不存在某个 Bean时注册当前 Bean | 提供默认实现 |
@ConditionalOnBean | 当 Spring 中存在某个 Bean时才注册 | 依赖其他 Bean |
@ConditionalOnProperty | 配置文件中有指定 key 且值满足条件 | 控制功能开关 |
@ConditionalOnClass | classpath 中存在某个类 | 判断是否引入某个 jar |
@ConditionalOnExpression | 使用 SpEL 表达式判断 | 更复杂的控制条件 |
@ConditionalOnWebApplication | 当前应用是 Web 类型 | Web 专属配置 |
@ConditionalOnNotWebApplication | 非 Web 应用时生效 | 通用应用配置 |
下面详细将两个我比较常用的:
重点 1:@ConditionalOnMissingBean
当容器中没有某个类型的 Bean时,才注册当前 Bean,常用于默认实现。
@Configuration
public class MyAutoConfiguration {
@Bean@ConditionalOnMissingBean(MyService.class)public MyService myService() {return new DefaultMyService();}
}
注意:
不能加在 @Component 类上!会绕过条件判断。
// 这个写法条件不会生效!
@Component
@ConditionalOnMissingBean(MyService.class)
public class DefaultMyService implements MyService { ... }
重点 2:@ConditionalOnProperty
基于配置文件中是否存在某个属性,以及其值是否匹配来控制 Bean 的注册。只有满足某个配置条件,才加载这个配置类或 Bean
@Configuration
@ConditionalOnProperty(prefix = "my.interceptor",name = "enabled",havingValue = "true",matchIfMissing = false
)
public class MyInterceptorAutoConfiguration {...
}
参数解释(这是重点):
参数名 | 作用 |
---|---|
prefix | 表示你定义的配置前缀,比如在 application.yml 中写的 my.interceptor.enabled |
name | 配置项的名称(搭配 prefix 使用) |
havingValue | 配置项的值为这个时,才成立 |
matchIfMissing | 为true的时候,如果用户根本没配置这个值,也算成立。也就是为ture等于默认开启 |
比如 你的配置文件这样写:
my:interceptor:enabled: true
那么这段 @ConditionalOnProperty 会生效,于是 @Configuration 类就会被加载,里面的拦截器、响应体处理器之类的 Bean才会被注册。
这是 Starter 模块设计中非常重要的可选开关机制,可以让用户自由决定是否启用你封装的功能。
很多我们常用的组件经常都有这种开关:
feign:
prometheus:
swagger:
另外,这些注解可以组合使用。
示例:组合使用
有时候我们希望配置生效还要保证 Bean 没有被覆盖,可以组合使用:
@Bean
@ConditionalOnMissingBean(MyService.class)
@ConditionalOnProperty(name = "my.feature.enabled", havingValue = "true", matchIfMissing = true)
public MyService defaultMyService() {return new DefaultMyService();
}
这段代码的意思是:
只有当 application.yml 中配置了 my.feature.enabled=true,并且容器中没有自定义的 MyService 实现,才使用这个默认实现。