Skip to content

自动配置是 Spring Boot 最核心、也最区别于普通 Spring 的东西。用 Spring Boot 时什么都没手动配,Redis、MyBatis、WebMVC 引入依赖就能直接用,背后就是自动配置在起作用。这篇把自动配置的原理拆开:@SpringBootApplication 背后是什么、条件注解怎么工作、怎么自己写一个自动配置。

想先了解"为什么会有 Spring、为什么后来又要有 Spring Boot"的历史背景,看《Spring 与 Spring Boot 的来历》。


一、为什么需要自动配置

先看普通 Spring 和 Spring Boot 的区别:

  • 普通 Spring:集成 Redis 要自己写 RedisTemplateRedisConnectionFactory 一堆 Bean;集成 MyBatis 要自己配 SqlSessionFactoryDataSource、Mapper 扫描……每个中间件都配一遍,重复又易错。
  • Spring Boot:引入 spring-boot-starter-data-redis,配置文件里写个 host/portRedisTemplate 就直接能用了——因为你没写的那些 Bean,自动配置帮你建好了

这就是自动配置的价值:把"每个中间件都要手动配一遍"的重复劳动,变成"引入依赖 + 写配置就能用"

二、@SpringBootApplication 背后的三件事

每个 Spring Boot 主类上都有 @SpringBootApplication,它其实是三个注解的合体:

java
@SpringBootConfiguration   // 等价于 @Configuration,标记这是配置类
@EnableAutoConfiguration   // 核心:开启自动配置的开关
@ComponentScan             // 扫描当前包下的组件
public @interface SpringBootApplication {}

其中 @EnableAutoConfiguration 是自动配置的总开关,它内部又做了两件事:

java
@AutoConfigurationPackage                                  // 记录主类所在包,用于默认包扫描
@Import(AutoConfigurationImportSelector.class)             // 关键:导入自动配置选择器
public @interface EnableAutoConfiguration {}

AutoConfigurationImportSelector 就是自动配置的"发动机"——它负责在启动时把该加载的自动配置类全部找出来、加载进来。

三、自动配置怎么"自动":条件注解

自动配置类不是无条件生效的,它们靠条件注解决定"要不要生效"。核心几个:

注解含义
@ConditionalOnClass类路径上某个类才生效
@ConditionalOnMissingClass类路径上没有某个类才生效
@ConditionalOnBean容器里某个 Bean 才生效
@ConditionalOnMissingBean容器里没有某个 Bean 才生效
@ConditionalOnProperty配置项满足条件才生效
@ConditionalOnWebApplication是 Web 应用才生效

RedisAutoConfiguration 举例(我之前写的《Redis 快速入门》里 Spring Boot 集成 Redis 就是它的功劳):

java
@ConditionalOnClass(RedisOperations.class)          // 有 Redis 相关类才加载
@EnableConfigurationProperties(RedisProperties.class) // 绑定 spring.data.redis.* 配置
public class RedisAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")  // 用户没自己定义才自动建
    public RedisTemplate<Object, Object> redisTemplate(...) { ... }
}

两个条件配合出的效果:你引入了 Redis 依赖(有类),又没自己定义 RedisTemplate(缺 Bean),它才帮你自动建一个。一旦你自己写了个 RedisTemplate,它就自动让位——这就是"约定优于配置"的精髓。

四、自动配置类怎么被发现的

那么多 starter,Spring Boot 怎么知道要加载哪些自动配置类?靠一个注册文件

  • 旧版(2.7 之前):META-INF/spring.factories 里的 EnableAutoConfiguration 键。
  • 新版(2.7+):META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,每行一个自动配置类的全限定名。

AutoConfigurationImportSelector 启动时读取所有 jar 里的这个文件,把自动配置类全列出来,再用条件注解逐个判断要不要加载。所以引入一个 starter,本质就是引入了它自带的自动配置类清单

五、自己写一个自动配置(自定义 starter 实战)

理解了原理,就能自己写一个 starter。以"一个打招呼的服务"为例:

1. 配置属性类

java
@ConfigurationProperties(prefix = "greeting")
public class GreetingProperties {
    private boolean enabled = true;
    private String name = "World";
    // getter / setter 省略
}

2. 自动配置类

java
@Configuration
@ConditionalOnClass(GreetingService.class)               // 有 GreetingService 才加载
@EnableConfigurationProperties(GreetingProperties.class) // 绑定 greeting.* 配置
public class GreetingAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean                                 // 用户没定义才建
    public GreetingService greetingService(GreetingProperties props) {
        return new GreetingService(props.isEnabled(), props.getName());
    }
}

3. 注册文件 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

com.example.GreetingAutoConfiguration

4. 依赖 spring-boot-autoconfigure

别人引入你的 starter 后,写一句 greeting.name=波哥GreetingService 就自动注入可用了——和官方 starter 一个体验。

六、几个要注意的点

  1. @ConditionalOnMissingBean 只在当前配置类内部生效:它只检查"目前扫描到的地方有没有这个 Bean",不能跨配置类保证唯一,多个自动配置类都想建同名 Bean 时顺序就很重要。
  2. 自动配置类的顺序:用 @AutoConfigureBefore / @AutoConfigureAfter 控制加载先后(比如自定义配置要在某个官方配置之后生效)。
  3. 条件注解按声明顺序判断:同一个类上多个 @ConditionalOnXxx从上到下依次判断,都满足才生效。
  4. 别在自动配置里做太重的事:自动配置应该只负责"建 Bean",业务逻辑放业务代码里,保持 starter 干净、可预测。

小结

  • 自动配置的价值:把"重复手动配 Bean"变成"引入依赖 + 写配置就能用"
  • @SpringBootApplication = @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan
  • @EnableAutoConfiguration 通过 @Import(AutoConfigurationImportSelector.class) 触发自动配置加载
  • 自动配置靠条件注解@ConditionalOnClass / @ConditionalOnMissingBean / @ConditionalOnProperty)决定是否生效
  • 自动配置类通过 AutoConfiguration.imports 文件注册被发现
  • 自定义 starter 四步:属性类 + 自动配置类 + 注册文件 + spring-boot-autoconfigure 依赖

想了解 Spring Boot 具体集成了哪些中间件、它们怎么用,看我整理的《Redis 快速入门》《RabbitMQ 快速入门》——这些文章里的 Spring Boot 集成代码,背后都是对应的 AutoConfiguration 在起作用。