Spring Boot 自动配置原理详解
适用于:Spring Boot 2.x / 3.x,偏向原理 + 面试
1. 为什么需要自动配置?
1.1 传统 Spring 配置的痛点
传统 Spring 应用一般要:
- 写 XML 或大量
@Configuration类 - 手动配置数据源、事务管理器、视图解析器、消息转换器……
- 新增一个技术栈(如 Redis、MQ)都要查一堆文档,抄一堆模板代码
问题:
- 重复劳动多,配置啰嗦
- 很多项目都是“复制上一份配置,改一点点”
- 配置错误很难排查
1.2 Spring Boot 的目标
Spring Boot 的核心理念可以简单概括为:
- 约定大于配置
- 能推断出来的,就不要你写
自动配置(Auto-Configuration)就是实现这个目标的关键机制:
根据 classpath、配置文件和当前环境,自动帮你注册合适的 Bean。
2. 自动配置涉及的核心注解与组件
2.1 @SpringBootApplication 做了什么?
典型启动类:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@SpringBootApplication 是一个复合注解,本质等价于:
@Configuration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {}
其中与自动配置直接相关的是:@EnableAutoConfiguration。
2.2 @EnableAutoConfiguration 的作用
精简理解:
- 告诉 Spring Boot:请根据当前依赖和环境,帮我把常用组件都自动配置好
- 底层是通过
@Import(AutoConfigurationImportSelector.class)把大量自动配置类导入到容器中
源码(简化):
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
// 允许排除某些自动配置类
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
重点:AutoConfigurationImportSelector 是自动配置机制的“中枢”。
2.3 AutoConfigurationImportSelector 的核心流程
这个类在启动时会做几件事(简化版逻辑):
-
加载候选自动配置类列表
- 从类路径下的配置文件读取所有“自动配置类”的全限定类名
- Spring Boot 3 之前:
META-INF/spring.factories - Spring Boot 3:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
-
去重 + 合并
-
处理排除项
- 注解上的
exclude/excludeName - 配置文件中的
spring.autoconfigure.exclude
- 注解上的
-
应用各种
@Conditional*条件,筛选出真正要生效的自动配置类 -
把这些类当作普通
@Configuration导入容器
伪代码示意(极度简化):
List<String> candidates = getCandidateConfigurations(); // 所有候选
candidates = removeDuplicates(candidates); // 去重
Set<String> exclusions = getExclusions(); // 需要排除的类
candidates.removeAll(exclusions); // 删除排除项
candidates = filter(candidates, autoConfigurationMetadata); // 按条件过滤
return candidates; // 导入容器
2.4 @Configuration vs @AutoConfiguration(Spring Boot 3)
在 Spring Boot 2.x 中,自动配置类一般写成:
@Configuration
public class WebMvcAutoConfiguration {
// ...
}
在 Spring Boot 3 中,官方推荐使用新的注解:
@AutoConfiguration
public class WebMvcAutoConfiguration {
// ...
}
@AutoConfiguration 本质上也是一种 @Configuration,只是专门标识“这是自动配置类”,并有一些默认优化(比如 proxyBeanMethods = false)。
3. 自动配置的加载流程(启动过程)
从应用启动的角度,把整个流程串起来:
- 调用
SpringApplication.run(...) SpringApplication创建并刷新ApplicationContext- 解析主类上的
@SpringBootApplication - 处理其中的
@EnableAutoConfiguration:- 导入
AutoConfigurationImportSelector
- 导入
AutoConfigurationImportSelector:- 读取所有候选自动配置类名(
spring.factories/AutoConfiguration.imports) - 去重、排除、按条件过滤
- 返回最终要导入的自动配置类列表
- 读取所有候选自动配置类名(
- Spring 容器当作普通配置类处理这些自动配置类:
- 解析
@Bean - 解析
@Import - 解析
@ConfigurationProperties等等
- 解析
- 所有 Bean 定义注册完毕,容器完成初始化
可以把它想象成一条流水线:
@SpringBootApplication
│
▼
@EnableAutoConfiguration
│ import
▼
AutoConfigurationImportSelector
│
├─ 读取候选类(配置文件)
├─ 去重 & 排除
├─ 条件评估(@Conditional 系列)
▼
注册自动配置类 -> 注册 Bean
4. 条件装配:@Conditional 家族
自动配置的精髓:有条件地注册 Bean。
这些条件就是一系列 @Conditional* 注解。
4.1 常见的条件注解
-
@ConditionalOnClass
classpath 中存在指定类时,配置才生效 -
@ConditionalOnMissingClass
classpath 中不存在某个类时才生效 -
@ConditionalOnBean
容器中已经存在指定 Bean 时生效 -
@ConditionalOnMissingBean
容器中没有指定 Bean 时生效(非常常见,用于“默认实现,可被用户覆盖”) -
@ConditionalOnProperty
某个配置属性存在 / 为特定值时生效 -
@ConditionalOnResource
classpath 中存在某个资源文件时生效 -
@ConditionalOnWebApplication/@ConditionalOnNotWebApplication
当前是否 Web 应用(Servlet / Reactive) -
@ConditionalOnExpression
SpEL 表达式结果为 true 时生效 -
@ConditionalOnJava
JDK 版本条件判断
4.2 典型例子:按 classpath 判断
@Configuration
@ConditionalOnClass(DataSource.class)
public class DataSourceAutoConfiguration {
// ...
}
含义:
- 只有在 classpath 上有
DataSource相关依赖时,才去自动配置数据源 - 换句话说:你引了哪种 starter,就会触发对应的自动配置
4.3 典型例子:默认 Bean,可被覆盖
@Bean
@ConditionalOnMissingBean
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
含义:
- 如果用户自己没有声明
ObjectMapperBean,则用默认的这一份 - 如果用户自定义了 Bean,自动配置这段就会“让路”
5. Spring Boot 2 vs 3:自动配置注册方式的演进
5.1 Spring Boot 2.x:spring.factories
老版本中,自动配置类通过 spring.factories 注册:
# src/main/resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.autoconfig.ExampleAutoConfiguration,com.example.autoconfig.OtherAutoConfiguration
特点:
- key 是
org.springframework.boot.autoconfigure.EnableAutoConfiguration - value 是一串自动配置类全限定名,用逗号分隔
5.2 Spring Boot 3:AutoConfiguration.imports
从 Spring Boot 2.7 开始,引入新的配置文件;到了 Spring Boot 3,已经完全改用:
# src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.autoconfig.ExampleAutoConfiguration
com.example.autoconfig.OtherAutoConfiguration
特点:
- 每行一个自动配置类
- 文件路径固定:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports - 更加专用、清晰,避免
spring.factories一坨东西混一起
如果你自己写 starter,要注意:
- Boot 2.x:可以用
spring.factories(2.7 也支持新方式) - Boot 3.x:必须使用
AutoConfiguration.imports,spring.factories已经不再支持自动配置注册
6. 从零实现一个自定义自动配置 + Starter
下面用一个非常简单的例子,走一遍完整流程。
6.1 模块划分建议
一般推荐拆成三层(也可以简化):
- 业务模块(可选)
- 比如
demo-library,只放业务类:HelloService、HelloProperties等
- 比如
- 自动配置模块
- 比如
demo-spring-boot-autoconfigure - 放自动配置类、
AutoConfiguration.imports等
- 比如
- Starter 模块
- 比如
demo-spring-boot-starter - 对外暴露,只需引入这一个依赖
- 比如
6.2 配置属性类
// prefix = demo.hello
@ConfigurationProperties(prefix = "demo.hello")
public class HelloProperties {
/**
* 前缀,默认 Hello
*/
private String prefix = "Hello";
/**
* 后缀,默认 !
*/
private String suffix = "!";
// getter/setter ...
}
6.3 业务 Service
public class HelloService {
private final HelloProperties properties;
public HelloService(HelloProperties properties) {
this.properties = properties;
}
public String sayHello(String name) {
return properties.getPrefix() + " " + name + properties.getSuffix();
}
}
6.4 自动配置类
Spring Boot 3 写法(推荐):
@AutoConfiguration
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public HelloService helloService(HelloProperties properties) {
return new HelloService(properties);
}
}
Spring Boot 2 写法可以用 @Configuration 替代 @AutoConfiguration。
说明:
@AutoConfiguration:标记这是一个自动配置类@EnableConfigurationProperties:让HelloProperties生效,绑定配置属性@ConditionalOnMissingBean:允许用户自定义自己的HelloService覆盖默认实现
6.5 在 AutoConfiguration.imports 中注册
src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
com.example.demo.autoconfigure.HelloAutoConfiguration
只要这个 jar 在 classpath 上,Spring Boot 就能自动发现并执行里面的自动配置。
6.6 Starter POM 示例
demo-spring-boot-starter/pom.xml 中典型依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>demo-spring-boot-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
用户项目只需要:
<dependency>
<groupId>com.example</groupId>
<artifactId>demo-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
再在 application.yml 中写:
demo:
hello:
prefix: "Hi"
suffix: "~~"
然后就可以直接注入使用:
@RestController
public class HelloController {
@Autowired
private HelloService helloService;
@GetMapping("/hello")
public String hello(String name) {
return helloService.sayHello(name);
}
}
不需要在业务项目里写任何 @Configuration 相关代码。
7. 自动配置是怎么“感知环境”的?
总结一下自动配置如何做决策——它主要看三类信息:
-
Classpath 上的依赖
- 有
spring-boot-starter-web:- 生效
DispatcherServletAutoConfiguration、WebMvcAutoConfiguration等
- 生效
- 有
spring-boot-starter-data-jpa:- 生效
DataSourceAutoConfiguration、HibernateJpaAutoConfiguration等
- 生效
- 有 Redis 相关依赖:
- 生效
RedisAutoConfiguration
- 生效
- 有
-
容器中已有的 Bean
- 借助
@ConditionalOnBean/@ConditionalOnMissingBean判断 - 典型模式:默认实现 + 用户可覆盖
- 借助
-
配置文件中的属性
@ConditionalOnProperty根据application.yml/application.properties中的值来控制- 比如很多
xxx.enabled属性,都是通过这个注解控制开关
你可以理解为:自动配置就是把“如果……就帮你配好……”这种规则写在了一大堆配置类里。
8. 自动配置的调试与问题排查
实际开发中,经常会遇到这些问题:
- “为什么某个自动配置生效了?”
- “为什么某个自动配置没有生效?”
- “我写的 Bean 为什么被覆盖 / 没有生效?”
这时候要学会看“条件评估报告”。
8.1 启动时打开 debug 日志
在配置文件中加入:
debug=true
启动后日志里会出现一段类似:
=========================
AUTO-CONFIGURATION REPORT
=========================
Positive matches:
...
Negative matches:
...
可以看到:
- 哪些自动配置类被激活(Positive matches)
- 哪些被禁用,以及禁用原因(Negative matches)
8.2 使用 Actuator /actuator/conditions 端点
引入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
配置开启端点:
management:
endpoints:
web:
exposure:
include: conditions
启动后访问:/actuator/conditions
可以看到结构化的 JSON 报告,比日志更方便分析。
8.3 常见排查套路
- 打开
debug=true或/actuator/conditions看具体是哪个条件没满足 - 检查 classpath 上是否有相关依赖(starter 引入是否正确)
- 检查有没有在注解 / 配置中
exclude了某些自动配置类 - 检查有没有手动声明了同名 Bean,导致自动配置失效或被覆盖
- 检查是否启用了错误的 profile / 配置文件
9. 常见面试题 & 回答要点
9.1 问:Spring Boot 自动配置的原理是什么?
答题要点:
- 启动类上的
@SpringBootApplication包含@EnableAutoConfiguration @EnableAutoConfiguration通过AutoConfigurationImportSelector加载所有候选自动配置类- 候选类来源于:
- Spring Boot 2.x:
META-INF/spring.factories - Spring Boot 3.x:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
- Spring Boot 2.x:
- 利用
@Conditional*注解,根据 classpath、已有 Bean、配置属性等条件筛选 - 最终把满足条件的自动配置类作为普通
@Configuration导入容器,注册 Bean
一句话总结:“EnableAutoConfiguration + AutoConfigurationImportSelector + 一堆带条件的配置类”。
9.2 问:Spring Boot 2 和 3 在自动配置上的主要区别?
答题要点:
- 注册自动配置类的方式发生变化:
- 2.x 使用
spring.factories - 3.x 使用
AutoConfiguration.imports,并废弃前者
- 2.x 使用
- 自动配置类推荐使用
@AutoConfiguration注解 - 底层核心思想不变:依然是
AutoConfigurationImportSelector负责加载 + 条件过滤
9.3 问:如何自定义一个 Spring Boot Starter?
答题思路可按步骤说:
- 定义业务 Bean 和配置属性类(
@ConfigurationProperties) - 编写自动配置类:
@AutoConfiguration/@Configuration- 配合
@ConditionalOnClass/@ConditionalOnMissingBean等 - 使用
@EnableConfigurationProperties激活属性绑定
- 在
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中注册自动配置类 - 创建 starter 模块:
- 依赖
spring-boot-starter和自动配置模块 - 对外发布这个 starter 依赖
- 依赖
- 使用时只需引入 starter + 少量配置即可
9.4 问:如何关闭某个自动配置?
三种常用方式:
- 在注解上排除:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class DemoApplication {}
- 在配置文件中排除:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
- 使用特定的开关属性(如果该自动配置提供了):
spring.datasource.enabled=false
10. 总结
- 自动配置本质上就是:一堆带条件的
@Configuration类 - 入口:
@SpringBootApplication→@EnableAutoConfiguration→AutoConfigurationImportSelector - 数据来源:classpath、已有 Bean、配置属性、运行环境
- 注册方式演进:
- 2.x:
spring.factories - 3.x:
AutoConfiguration.imports
- 2.x:
- 使用层面要掌握:
- 怎么关(exclude / 属性开关)
- 怎么查(debug 日志、
/actuator/conditions) - 怎么写(自定义自动配置 + starter)
如果你能把这里的流程用自己的话完整讲一遍,再结合一两个真实项目中的例子(比如“我们自定义了一个xx starter”),在面试里基本就能拿到这块的高分。
1377

被折叠的 条评论
为什么被折叠?



