前言
用过 SpringBoot 的同学都知道,相比于 SSM,SpringBoot 最大亮点就是自动配置 。 原生 Spring 开发:需要手动配置大量 XML、Bean、数据库连接池、视图解析器等,配置文件一大堆。 SpringBoot:引入 starter 依赖,少量配置甚至零配置,直接使用组件。
很多人只会使用,但经常被问:
- SpringBoot 自动配置原理是什么?
@EnableAutoConfiguration作用?- starter 是什么?
- 条件注解有哪些?什么时候生效?
- SPI 机制在自动配置中扮演什么角色?
本文从底层源码角度,把整套自动配置流程讲清楚。
环境:SpringBoot 2.x
一、核心入口注解 @SpringBootApplication
打开 SpringBoot 启动类注解:
java
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@SpringBootApplication是复合注解,源码:
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {}
由 3 个核心注解组成:
@SpringBootConfiguration:本质就是@Configuration,代表当前类是配置类,可以注册 Bean@ComponentScan:组件扫描,默认扫描当前启动类所在包及其子包下所有@Component、@Service、@Controller等@EnableAutoConfiguration:自动配置核心开关(本篇重点)
二、@EnableAutoConfiguration 源码解析
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
两个关键注解:
@AutoConfigurationPackage:自动配置包,把启动类所在包注册进去,用于扫描包路径@Import(AutoConfigurationImportSelector.class):导入自动配置选择器,这是自动配置核心!
@Import是 Spring 原生注解,可以导入配置类、ImportSelector、ImportBeanDefinitionRegistrar。AutoConfigurationImportSelector实现了ImportSelector接口,重写selectImports()方法。
selectImports () 方法作用
selectImports()返回全类名字符串数组,Spring 会把返回的所有类当成配置类,加载到容器。
AutoConfigurationImportSelector内部会:
- 读取
META-INF/spring.factories文件 - 获取 key=
org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的所有配置类全类名列表 - 过滤掉 exclude 排除的自动配置类
- 返回剩下的配置类名称数组交给 Spring 容器加载
SpringBoot SPI 机制 :
spring.factories就是 SPI 配置文件。 路径:META-INF/spring.factories,在 spring-boot-autoconfigure 包里面。
spring.factories 示例片段:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration
每一行就是一个自动配置类。
三、自动配置类长什么样(以 DataSourceAutoConfiguration 举例)
打开DataSourceAutoConfiguration,里面大量条件注解。
java
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
// 内部创建DataSource Bean
}
条件注解(核心!决定 Bean 要不要创建)
| 注解 | 含义 |
|---|---|
@ConditionalOnClass |
classpath 下存在指定类,配置才生效 |
@ConditionalOnMissingBean |
容器中不存在这个 Bean,才创建 Bean(用户自定义 Bean 优先) |
@ConditionalOnProperty |
配置文件存在指定配置项,并且匹配值 |
@ConditionalOnWebApplication |
当前是 web 环境才生效 |
@ConditionalOnNotWebApplication |
非 web 环境生效 |
核心规则:自动配置是 "兜底",如果我们自己定义了 Bean,SpringBoot 自动配置就不生效 。原理就是
@ConditionalOnMissingBean。
@EnableConfigurationProperties
绑定配置文件application.yml/application.properties和属性类。 DataSourceProperties对应 spring.datasource 前缀配置,读取 yml 里面配置。
spring:
datasource:
url: jdbc:mysql://xxx
username: root
属性类@ConfigurationProperties(prefix = "spring.datasource")接收配置。
四、完整自动配置执行流程(一句话总结)
启动类打上 @SpringBootApplication,其中 @EnableAutoConfiguration 导入 AutoConfigurationImportSelector;该类通过 SPI 读取 META-INF/spring.factories,拿到所有自动配置类;每个自动配置类带有条件注解;Spring 容器启动时,根据条件注解判断是否实例化 Bean;满足条件就创建组件,不满足直接跳过。

详细分步:
- 执行
SpringApplication.run(),启动 Spring 容器 - 解析启动类
@SpringBootApplication注解 @EnableAutoConfiguration导入AutoConfigurationImportSelectorAutoConfigurationImportSelector读取spring.factories文件,加载候选自动配置类列表- 过滤 exclude 排除的配置类
- Spring 依次解析每一个自动配置类
- 检查类上条件注解是否满足环境
- 条件满足:向容器注册 Bean;条件不满足:跳过该配置类
- 自动配置类里面的属性通过
@ConfigurationProperties读取 yml 配置

五、什么是 starter?
starter = 依赖坐标 + 自动配置类
- starter 本身几乎没有代码,只是 pom.xml,帮你引入需要的所有依赖;
- 真正自动配置逻辑在
spring-boot-autoconfigure包;
举例:spring-boot-starter-web
- pom 引入 tomcat、springmvc 等依赖;
- 自动配置:
WebMvcAutoConfiguration,条件满足自动注册 DispatcherServlet、视图解析器等 Bean。
自定义 starter 思路:
- 创建模块,编写配置类 + 条件注解
- 编写
META-INF/spring.factories,写入自动配置类全类名- 打包,其他项目引入依赖即可自动配置
六、自动配置的优先级(覆盖自动配置 Bean)
SpringBoot 自动配置 Bean 优先级: 用户自定义 Bean > 自动配置 Bean 原因:自动配置使用@ConditionalOnMissingBean。只要你在配置类自己定义 DataSource Bean,SpringBoot 自动配置就不会创建。
示例:自定义数据源,覆盖自动配置
java
@Configuration
public class MyDataSourceConfig{
@Bean
public DataSource dataSource(){
// 自定义数据源
return new HikariDataSource();
}
}
容器存在 dataSource Bean,DataSourceAutoConfiguration里面的 Bean 不会实例化。
七、常见踩坑点
- 组件扫描范围问题
@ComponentScan默认扫描启动类所在包及子包。如果 Bean 放在启动类包之外,无法被扫描,需要手动指定scanBasePackages。 - spring.factories 位置写错,自定义 starter 自动配置不生效 必须放在
resources/META-INF/spring.factories。 - 条件注解理解错误
@ConditionalOnClass判断的是classpath 是否存在这个类,不是容器有没有 Bean。 - SpringBoot 2.7 之后,不再推荐 spring.factories 方式注册自动配置,改用
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件。
面试主要问 spring.factories 这套经典原理,2.7 + 新版本可以作为补充。
八、面试高频问答
Q1:SpringBoot 自动配置原理是什么?
A:核心是
@EnableAutoConfiguration,通过AutoConfigurationImportSelector利用 SPI 读取spring.factories加载大量自动配置类;配置类带有条件注解,容器启动时根据当前环境判断是否注册 Bean;结合@ConfigurationProperties读取配置文件。
Q2:@EnableAutoConfiguration 和 @ComponentScan 区别?A:
@ComponentScan扫描开发者自己写的 Bean;@EnableAutoConfiguration加载 SpringBoot 内置的自动配置 Bean。
Q3:@ConditionalOnMissingBean 作用?A:容器不存在指定 Bean 的时候才创建。目的:用户自定义 Bean 优先,SpringBoot 自动配置作为兜底。
Q4:starter 和 autoconfigure 包关系?A:starter 是依赖聚合,方便引入 jar 包;autoconfigure 存放自动配置类的源码。
Q5:如何关闭某个自动配置?A:启动类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})排除指定自动配置类。
Q6:SpringBoot3.x 自动配置 SPI 有什么变化?A:SpringBoot2.7 开始废弃 spring.factories 的自动配置方式,改用
AutoConfiguration.imports文件,但是底层思想不变。
结语
SpringBoot 自动配置本质就是Spring 原生注解 + SPI 扩展机制 + 条件注解组合而成,不是什么黑魔法。 理解这套原理之后,不仅面试游刃有余,也可以自己动手开发自定义 starter。 很多开发只会使用 SpringBoot,但是看不懂底层,这也是区分初级后端和中级后端的一个考点。