1. 概述
Spring Boot 的自动配置(auto-configuration)特性极大简化了传统 Spring 应用的配置流程。通过合理的默认配置和条件化加载机制,开发者可以快速搭建可运行的应用。
本文将重点解析 org.springframework.boot.autoconfigure
和 org.springframework.boot.autoconfigure.condition
两个包中的核心注解,帮助你掌握如何控制自动配置的行为,尤其在开发自定义 Starter 或调试配置冲突时非常实用。
2. @SpringBootApplication
这是每个 Spring Boot 项目的“门面”注解,通常标注在主启动类上 ✅
@SpringBootApplication
class VehicleFactoryApplication {
public static void main(String[] args) {
SpringApplication.run(VehicleFactoryApplication.class, args);
}
}
它到底做了什么?
@SpringBootApplication
是一个组合注解,等价于同时使用以下三个注解:
@Configuration
:标记该类为配置类@EnableAutoConfiguration
:启用自动配置机制@ComponentScan
:开启组件扫描(默认扫描当前包及其子包)
⚠️ 踩坑提醒:如果你手动拆分了这三个注解,记得确保 @ComponentScan
的包路径覆盖你的业务组件,否则可能发现 Bean 没有被扫描到。
3. @EnableAutoConfiguration
顾名思义,这个注解用于开启自动配置功能。Spring Boot 会根据 classpath 中存在的依赖(如 spring-boot-starter-data-jpa
、spring-boot-starter-web
)自动配置相应的 Bean。
虽然通常通过 @SpringBootApplication
间接启用,但也可以显式使用:
@Configuration
@EnableAutoConfiguration
class VehicleFactoryConfig {}
✅ 建议:在自定义 Starter 或测试配置时,可以单独使用此注解进行隔离验证。
4. 自动配置条件注解
当我们开发自定义自动配置时,往往不希望无条件生效,而是根据某些环境条件来决定是否加载。Spring Boot 提供了一套强大的条件化注解,全部位于 org.springframework.boot.autoconfigure.condition
包下。
这些注解可以作用于:
@Configuration
类@Bean
方法
下面我们逐个解析常用条件注解。
4.1 @ConditionalOnClass 与 @ConditionalOnMissingClass
根据 classpath 中是否存在指定类来决定是否加载配置。
@Configuration
@ConditionalOnClass(DataSource.class)
class MySQLAutoconfiguration {
// 只有存在 DataSource 类时才会加载此配置
}
✅ 典型场景:只有引入了 spring-jdbc
依赖时才配置数据源相关 Bean。
⚠️ 注意:@ConditionalOnClass
的类必须是编译期可访问的,否则会导致编译错误。若类来自可选依赖,建议配合 name
属性使用字符串类名:
@ConditionalOnClass(name = "com.example.OptionalService")
4.2 @ConditionalOnBean 与 @ConditionalOnMissingBean
根据IOC 容器中是否存在某个 Bean 来决定是否创建当前 Bean。
@Bean
@ConditionalOnBean(name = "dataSource")
LocalContainerEntityManagerFactoryBean entityManagerFactory() {
// 只有当容器中已存在名为 dataSource 的 Bean 时,才创建 entityManagerFactory
}
✅ 实战技巧:@ConditionalOnMissingBean
非常有用,常用于“用户未配置时提供默认实现”的场景,避免 Bean 冲突。
例如:
@Bean
@ConditionalOnMissingBean
public MyService myService() {
return new DefaultMyServiceImpl();
}
4.3 @ConditionalOnProperty
根据 application.properties 或 application.yml 中的配置项值 来决定是否生效。
@Bean
@ConditionalOnProperty(
name = "usemysql",
havingValue = "local"
)
DataSource dataSource() {
// 只有 usemysql=local 时才创建此数据源
}
支持更多属性:
matchIfMissing = true
:配置项不存在时也视为匹配prefix
:可指定前缀,如app.datasource
示例:
@ConditionalOnProperty(prefix = "app.feature", name = "cache", havingValue = "enabled")
4.4 @ConditionalOnResource
只有当指定资源存在时才加载配置。
@ConditionalOnResource(resources = "classpath:mysql.properties")
Properties additionalProperties() {
// 只有 classpath 下存在 mysql.properties 时才加载
}
✅ 适用场景:加载外部配置文件、证书、脚本等资源依赖的配置。
4.5 @ConditionalOnWebApplication 与 @ConditionalOnNotWebApplication
根据当前应用是否为 Web 应用做判断。
@ConditionalOnWebApplication
HealthCheckController healthCheckController() {
// 只在 Web 环境下注册该 Controller
}
Spring 通过检测 classpath 中是否存在 Servlet、Spring Web 等相关类来判断。
✅ 常见用途:Starter 包中区分 Web 和非 Web 场景的配置。
4.6 @ConditionalOnExpression
使用 SpEL 表达式进行更复杂的条件判断。
@Bean
@ConditionalOnExpression("${usemysql} && ${mysqlserver == 'local'}")
DataSource dataSource() {
// 只有 usemysql=true 且 mysqlserver=local 时才创建
}
⚠️ 注意:SpEL 中引用的配置项必须能解析为布尔值或可比较类型,否则会抛异常。
✅ 优势:逻辑灵活,适合多条件组合判断。
4.7 @Conditional
当内置条件注解无法满足需求时,可自定义条件判断逻辑。
你需要实现 Condition
接口,并在注解中引用:
@Conditional(HibernateCondition.class)
Properties additionalProperties() {
//...
}
HibernateCondition
示例:
class HibernateCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 自定义判断逻辑,返回 true 则加载
return context.getClassLoader().getResource("hibernate.cfg.xml") != null;
}
}
✅ 高级用法:可用于环境探测、版本兼容性判断、License 校验等复杂场景。
5. 总结
Spring Boot 的自动配置机制之所以强大,核心就在于这套条件化装配体系。掌握这些 @Conditional
系列注解,不仅能帮助你理解自动配置的底层原理,还能在开发自定义 Starter、解决配置冲突、实现环境差异化配置时游刃有余。
✅ 关键要点回顾:
@SpringBootApplication
是组合注解,简化启动类配置- 条件注解是自动配置的“开关”,按需加载
@ConditionalOnMissingBean
是避免冲突的利器- 复杂逻辑可用
@Conditional
自定义判断
所有示例代码已托管至 GitHub,便于查阅和复用:
👉 https://github.com/tech-tutorial/spring-boot-annotations-demo