1. 概述

Spring Boot 的自动配置(auto-configuration)特性极大简化了传统 Spring 应用的配置流程。通过合理的默认配置和条件化加载机制,开发者可以快速搭建可运行的应用。

本文将重点解析 org.springframework.boot.autoconfigureorg.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-jpaspring-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


原始标题:Spring Boot 中的注解