SpringBoot 自动配置是如何实现的?


面试考察点

  1. 注解体系理解:面试官不仅仅是想知道你听过 @EnableAutoConfiguration 这个名字,更想知道你能不能把它拆开,说清楚每个注解的作用和它们之间的组合关系。
  2. SPI 机制掌握:Spring Boot 自动配置的核心加载方式是 SPI(Spring Factories 机制),面试官想考察你是否理解这个类加载机制。
  3. 条件过滤原理:自动配置类那么多,不可能全部生效。面试官想知道你是否清楚 @Conditional 系列注解的工作原理,以及 "用户自定义优先" 这个设计理念。

核心答案

Spring Boot 自动配置的实现可以概括为 三个关键步骤

步骤做了什么核心组件
1. 入口触发@EnableAutoConfiguration 注解触发自动配置@SpringBootApplication 内含
2. 全量加载通过 SPI 机制从 spring.factories 全量加载自动配置类AutoConfigurationImportSelector
3. 条件过滤通过 @ConditionalOnXxx 注解按条件过滤,满足的才生效各种 Condition 实现

一句话总结:先全量加载,再按条件过滤,用户自定义优先。

深度解析

一、从入口注解开始

一切从 @SpringBootApplication 这个注解开始。它是一个复合注解,拆开看:

// @SpringBootApplication 源码(简化)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@SpringBootConfiguration       // ① 等同于 @Configuration,标记配置类
@EnableAutoConfiguration       // ② 核心!开启自动配置
@ComponentScan(                // ③ 组件扫描
    excludeFilters = {
        @Filter(type = FilterType.CUSTOM,
                classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM,
                classes = AutoConfigurationExcludeFilter.class)
    })
public @interface SpringBootApplication {
    // ...
}

三个注解各司其职:

  • @SpringBootConfiguration:本质就是 @Configuration,表示当前类是一个配置类,可以声明 @Bean 方法。
  • @ComponentScan:扫描当前启动类所在包及子包下的 @Component@Service@Controller 等注解。这就是为什么你的业务类必须放在启动类同包或子包下。
  • @EnableAutoConfiguration这才是自动配置的关键入口,下面重点展开。

二、@EnableAutoConfiguration 做了什么?

// @EnableAutoConfiguration 源码(简化)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@AutoConfigurationPackage       // 自动配置包路径
@Import(AutoConfigurationImportSelector.class)  // 核心!导入选择器
public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY =
        "spring.boot.enableautoconfiguration";

    // 排除指定的自动配置类
    Class<?>[] exclude() default {};

    // 按名称排除
    String[] excludeName() default {};
}

关键就在 @Import(AutoConfigurationImportSelector.class) 这一行。AutoConfigurationImportSelector 是整个自动配置的 "调度中心",它负责把所有符合条件的自动配置类加载到 Spring 容器中。

三、自动配置的完整加载流程

上图是自动配置从触发到生效的完整链路,按阶段拆解:

  • 阶段一(入口触发)@EnableAutoConfiguration 注解通过 @Import 导入 AutoConfigurationImportSelector,这是整个流程的起点。
  • 阶段二(全量加载)AutoConfigurationImportSelector 调用 SpringFactoriesLoader,扫描 classpath 下所有 jar 包的 META-INF/spring.factories 文件,读出所有以 EnableAutoConfiguration 为 key 的配置类全限定名。这一步是 "全量加载",有多少加载多少,不挑食。
  • 阶段三(去重排除):对加载到的配置类去重,排除通过 exclude 属性明确指定的类,排除通过 spring.autoconfigure.exclude 配置项指定的类。
  • 阶段四(条件过滤):这是最关键的一步。遍历剩余的候选配置类,逐个检查 @ConditionalOnXxx 注解,只有满足条件的才会被注册到容器中。
  • 阶段五(注册生效):通过条件过滤的配置类正式生效,其内部的 @Bean 方法会被执行,向 Spring 容器注册对应的 Bean。

四、以 DataSourceAutoConfiguration 为例

光说流程太抽象,拿一个具体的自动配置类来看看:

// DataSourceAutoConfiguration.java(简化版源码)
@AutoConfiguration
@ConditionalOnClass(DataSource.class)           // ① classpath 有 DataSource 类
@ConditionalOnMissingBean(DataSource.class)      // ② 容器中没有自定义 DataSource
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource(DataSourceProperties properties) {
        // 根据 application.yml 中的配置创建数据源
        return DataSourceBuilder.create()
                .url(properties.getUrl())
                .username(properties.getUsername())
                .password(properties.getPassword())
                .build();
    }
}

这个类只有满足 两个条件 才会生效:

  • 条件一@ConditionalOnClass(DataSource.class) —— classpath 上存在 DataSource 类,说明你引入了数据库相关的依赖(比如 spring-boot-starter-jdbc 或 MyBatis)。如果你项目里压根没引入数据库依赖,这个配置类直接跳过。
  • 条件二@ConditionalOnMissingBean(DataSource.class) —— 容器中还没有 DataSource 类型的 Bean。如果你自己手动定义了一个 @Bean DataSource,那 Spring Boot 就不再自动创建了,用户自定义优先

这就是 "约定优于配置" 的实现方式:

  • 你什么都不配 → Spring Boot 用默认值帮你创建(约定)
  • 你自己配了 → Spring Boot 退让,用你的(用户优先)
  • 你引入了依赖 → 自动配置生效;没引入 → 自动配置不生效

五、@Conditional 系列注解一览

Spring Boot 提供了一整套条件注解,面试的时候至少能说出几个常用的:

注解条件典型场景
@ConditionalOnClassclasspath 中存在指定类引入了某个依赖才生效
@ConditionalOnMissingClassclasspath 中不存在指定类没引入某个依赖才生效
@ConditionalOnBean容器中已存在指定 Bean某个 Bean 已注册才生效
@ConditionalOnMissingBean容器中不存在指定 Bean最常用,用户没配才生效
@ConditionalOnProperty配置文件中有指定属性spring.datasource.url 配了才生效
@ConditionalOnWebApplication当前是 Web 应用只有 Web 环境才生效
@ConditionalOnNotWebApplication当前不是 Web 应用非 Web 环境才生效
@ConditionalOnExpressionSpEL 表达式为 true复杂条件判断

其中 @ConditionalOnMissingBean 出现频率最高,它是实现 "用户自定义优先" 的关键。

六、自定义一个 Starter

理解了自动配置原理,自定义 Starter 就是顺理成章的事。三步搞定:

第一步:写一个自动配置类

@AutoConfiguration
@ConditionalOnClass(MyService.class)         // 有 MyService 才生效
@ConditionalOnProperty(prefix = "my.starter",
        name = "enabled", havingValue = "true",
        matchIfMissing = true)                // 默认生效
public class MyAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public MyService myService(MyProperties props) {
        return new MyService(props.getPrefix());
    }
}

第二步:注册到 spring.factories(Spring Boot 2.7 之前)

# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.example.MyAutoConfiguration

Spring Boot 2.7+ 推荐用新方式:

# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.MyAutoConfiguration

第三步:引入依赖就自动生效

其他项目只要在 pom.xml 中引入这个 Starter 的依赖,MyService 就会自动注册到容器中,零配置。

面试高频追问

  1. 追问一:自动配置类一定会生效吗?

    • 不一定。自动配置类必须通过 @ConditionalOnXxx 的条件检查才会生效。比如 DataSourceAutoConfiguration 需要 classpath 上有数据库驱动;RedisAutoConfiguration 需要引入 spring-boot-starter-data-redis。这也是为什么引入不同 Starter 会自动拥有不同能力的原因。
  2. 追问二:如何排查某个自动配置类有没有生效?

    • application.yml 中加上 debug: true,启动时会在控制台打印 CONDITIONS EVALUATION REPORT,列出哪些自动配置类生效了、哪些没生效以及原因。也可以用 /actuator/conditions 端点(Actuator)来查看。
  3. 追问三:@ComponentScan@EnableAutoConfiguration 有什么区别?

    • @ComponentScan 扫描的是你项目里自己写的 @Component@Service@Controller 等注解标记的类,范围是启动类所在包及子包。@EnableAutoConfiguration 加载的是第三方 jar 包里的 xxxAutoConfiguration 类,通过 SPI 机制从 spring.factories 中读取。两者互补:一个管你自己的类,一个管框架的类。
  4. 追问四:Spring Boot 3.x 的自动配置有什么变化?

    • 最大的变化是 spring.factoriesEnableAutoConfiguration 的注册方式被废弃了,改为使用 AutoConfiguration.imports 文件。另外自动配置类从 @Configuration 改为使用 @AutoConfiguration 注解(Spring Boot 3.0 新增),语义更明确。

常见面试变体

  • "说一下 @SpringBootApplication 注解的组成?"
  • "@ConditionalOnMissingBean 是什么意思?有什么用?"
  • "如何自定义一个 Spring Boot Starter?"
  • "spring.factories 文件的作用是什么?"

记忆口诀

注解入口 → SPI 全量加载 → 条件过滤 → 满足的生效

核心设计理念:约定优于配置,用户自定义优先@ConditionalOnMissingBean

总结

Spring Boot 自动配置的本质就是:@EnableAutoConfiguration 通过 @Import 导入 AutoConfigurationImportSelector,利用 SPI 机制从 spring.factories 全量加载候选配置类,再通过 @ConditionalOnXxx 系列注解按条件过滤,最终只有满足条件的配置类才会向容器注册 Bean。其中 @ConditionalOnMissingBean 保证了 "用户自定义优先" 的核心设计。面试时把 "全量加载 + 条件过滤 + 用户优先" 这条线讲清楚就够了。