Spring Boot 自动配置原理详解

Spring Boot 自动配置原理详解

定位:02 篇,讲透自动配置的完整触发链:从 @EnableAutoConfiguration 到候选清单加载、条件过滤、用户优先机制,以及调试排查手段

适用版本:Spring Boot 3.x(JDK 17+)

前置:条件装配注解族见 Framework-05篇


目录


一、触发链

自动配置由 @EnableAutoConfiguration(含在 @SpringBootApplication 内)触发,全链路:

复制代码
@SpringBootApplication
  └── @EnableAutoConfiguration
        └── @Import(AutoConfigurationImportSelector.class)   ← 关键
              └── selectImports():
                    ① 读取候选自动配置类清单
                    ② 去重、按排除项过滤(exclude)
                    ③ 返回全限定名数组 → 注册为配置类

核心角色 AutoConfigurationImportSelector:它实现 DeferredImportSelector(延迟导入),在用户配置类处理完之后才导入自动配置------这是"用户优先"的顺序基础。


二、候选清单加载

2.1 清单位置(版本差异,高频考点)

版本 清单文件
2.7 及以前 META-INF/spring.factories(EnableAutoConfiguration 键)
3.x META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(每行一个类名)

各依赖的 jar(如 spring-boot-autoconfigure、各 starter 的配套包)都在自己的该文件里声明自己的自动配置类;Selector 聚合所有 jar 的清单。

2.2 候选数量级

一个典型 Web 应用聚合到的候选有上百个,但绝大多数因条件不满足被跳过------"加载清单"不等于"全部装配"。


三、条件过滤

3.1 自动配置类 = 配置类 + 条件

java 复制代码
@AutoConfiguration
@ConditionalOnClass(DataSource.class)          // classpath 有相关类才考虑
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean                   // 用户没定义才注册默认
    public DataSource dataSource(...) { ... }
}

条件注解回顾(FW-05):

注解 判断
@ConditionalOnClass / OnMissingClass classpath 存在/缺少类
@ConditionalOnProperty 配置属性开关
@ConditionalOnBean / OnMissingBean 容器有/无某 Bean

3.2 评估时机

条件在 Bean 定义注册阶段评估。自动配置类被注册为配置类后,其 @Conditional 决定是否真正生效------不满足则整个类(含其中 @Bean)跳过。

3.3 三层过滤漏斗

复制代码
上百个候选类
  ↓ @ConditionalOnClass(有依赖才进门)
几十个
  ↓ @ConditionalOnProperty / OnWebApplication 等
更少
  ↓ @ConditionalOnMissingBean(用户没定义才装)
最终实际生效的自动配置

四、用户优先机制

"约定大于配置"必须保证用户定义永远能覆盖默认,靠两点:

  1. @ConditionalOnMissingBean:自动配置注册默认 Bean 前检查"容器是否已有",有则让位;

  2. 处理顺序 :AutoConfigurationImportSelector 是 DeferredImportSelector,用户配置类先处理,自动配置后处理------所以 OnMissingBean 检查时用户的定义已就绪。

    用户:@Bean DataSource 自定义 → 先注册
    自动配置:OnMissingBean(DataSource) → 发现已有 → 跳过
    结果:用户的生效,不冲突

若顺序反了(自动配置先处理),OnMissingBean 看不到用户定义,就会冲突或覆盖------这就是自定义配置类间乱用 OnBean 会误判的原因(FW-05)。


五、常见自动配置举例

自动配置类 装什么
WebMvcAutoConfiguration DispatcherServlet、内嵌容器、静态资源
DataSourceAutoConfiguration 数据源(需配置 url 或内嵌库)
RedisAutoConfiguration RedisTemplate/StringRedisTemplate
JacksonAutoConfiguration ObjectMapper(JSON 转换)
TaskExecutionAutoConfiguration 默认线程池(@Async 兜底)

理解套路后,看任何"starter 引入了就自动能用"的现象,都能定位到对应的自动配置类。


六、调试与排查

"为什么没生效/为什么这样配"的标准手段:

手段 用法
条件报告 启动加 --debug(或 debug: true),打印 ConditionEvaluationReport:列出每个自动配置的匹配/不匹配及原因
Actuator /actuator/conditions 运行时查看
排除项 @SpringBootApplication(exclude = XxxAutoConfiguration.class) 或 spring.autoconfigure.exclude

排查"某 Bean 没出现"的顺序:

复制代码
① 相关依赖(starter)是否引入 → OnClass 进门条件
② 是否需要配置属性(如 datasource 需要 url)→ OnProperty
③ 是否被自己误定义/误排除 → OnMissingBean/exclude
④ 看 --debug 报告中该配置类的具体判定

七、总结

  1. 触发链:@SpringBootApplication → @EnableAutoConfiguration → @Import(AutoConfigurationImportSelector) → 读清单、过滤、注册。
  2. 候选清单:2.7 前在 spring.factories,3.x 在 AutoConfiguration.imports;聚合所有 jar 的声明,候选上百但按需装配。
  3. 条件过滤漏斗:OnClass(有依赖)→ OnProperty 等 → OnMissingBean(用户没定义),层层收敛到实际生效集。
  4. 用户优先:DeferredImportSelector 保证用户配置先处理 + OnMissingBean 让位,实现"默认生效又处处可覆盖"。
  5. 排查:--debug 的 ConditionEvaluationReport 是自动配置的"透视镜",配合 exclude 精确控制。

八、常见高频面试题

1. 详细说说 Spring Boot 自动配置的原理。

要点:链路上,@SpringBootApplication 的 @EnableAutoConfiguration 通过 @Import 引入 AutoConfigurationImportSelector;它读取所有 jar 中的自动配置类清单(3.x 为 META-INF/spring/...AutoConfiguration.imports),聚合去重后作为候选;每个自动配置类带 @Conditional 条件(OnClass/OnProperty/OnMissingBean 等),在注册阶段按条件过滤,只有满足的才真正装配默认 Bean。本质是"大量预写配置类 + 条件化按需生效"。

2. spring.factories 和 AutoConfiguration.imports 的区别?

要点:都是声明自动配置类清单的文件,是版本演进关系。2.7 及以前用 META-INF/spring.factories(键值对,EnableAutoConfiguration=类名列表,还承载其它 SPI 式键);3.x 改用专门的 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(每行一个类名,语义单一)。迁移时旧文件不再被读取,是 Boot 2→3 升级的常见坑。

3. 自动配置怎么保证不和用户自定义的 Bean 冲突?

要点:两机制配合。① @ConditionalOnMissingBean------自动配置注册默认 Bean 前检查容器中是否已有该类型/名称的 Bean,有则跳过让位;② 顺序保证------AutoConfigurationImportSelector 是 DeferredImportSelector,用户配置类先处理、自动配置后处理,所以检查时用户定义已就绪。从而实现"约定大于配置":默认生效,用户一旦自定义即覆盖,无冲突。

4. @EnableAutoConfiguration 是如何工作的?

要点:它通过 @Import 导入 AutoConfigurationImportSelector,后者实现 DeferredImportSelector,在配置类处理后期执行 selectImports():读取候选清单、去除重复与显式排除项(@EnableAutoConfiguration(exclude=...) 或 spring.autoconfigure.exclude)、返回要导入的自动配置类名。这些类随后按各自 @Conditional 条件决定是否生效。它是连接"注解开关"与"候选加载"的桥梁。

5. 怎么排除某个自动配置?

要点:三种方式。① 注解:@SpringBootApplication(exclude = XxxAutoConfiguration.class) 或 excludeName 按类名;② 配置:spring.autoconfigure.exclude=全限定名(可多个);③ 精确控制:不排除整个类,而是自己定义同类型 Bean 让 OnMissingBean 让位。常见场景:关闭默认数据源自动配置(用自定义)、关闭安全默认拦截等。

6. 为什么我引入了依赖但某个 Bean 没有自动配置出来?

要点:按条件漏斗排查。① OnClass 是否满足(依赖是否真引入且版本对);② 是否依赖配置属性(如 DataSource 需要 spring.datasource.url,缺了就不装);③ 是否被自己误排除或误定义了同类型 Bean;④ 用 --debug 启动看 ConditionEvaluationReport 中该自动配置类的具体不匹配原因,这是最直接的定位手段。

7. 自动配置类上的 @ConditionalOnClass 在类不存在时不会 ClassNotFoundException 吗?

要点:不会,这正是设计巧妙处。条件评估在解析配置类的元数据阶段进行,通过 ASM 字节码读取注解信息而不真正加载该类;若 @ConditionalOnClass 指定的类不在 classpath,整个自动配置类在条件判定时即被跳过,不会触发类加载,也就没有 ClassNotFoundException。这让"按依赖存在与否装配"安全可行。

8. 自动配置和组件扫描的区别?

要点:两者都往容器注册东西,但来源与目的不同。组件扫描(@ComponentScan)发现用户代码中的 @Component/@Service 等,注册业务 Bean;自动配置来自依赖 jar 的清单文件,按条件装配框架默认组件(数据源、模板、MVC)。扫描是"找到你写的",自动配置是"按依赖给你默认的"。两者在 refresh 阶段都产出 BeanDefinition。

9. 什么是 DeferredImportSelector?为什么自动配置用它?

要点:ImportSelector 的延迟变体,其导入的配置类在所有普通 @Configuration 类(包括用户配置)处理完之后才处理。自动配置用它,是为了保证用户定义先注册------这样自动配置里的 @ConditionalOnMissingBean 才能看到用户 Bean 并正确让位,实现"用户优先、默认兜底"。若用普通 Import 同时处理,顺序无法保证,覆盖语义会出错。

10. 如何自定义一个自动配置(让别人引入你的 jar 就自动生效)?

要点:① 写 @AutoConfiguration(或 @Configuration + @Conditional)配置类,内含 @Bean 定义,配好 @ConditionalOnClass/OnProperty/OnMissingBean 等条件;② 把类全限定名写入 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(3.x);③ 随你的 starter jar 发布。这样使用方引入依赖即自动装配,可用属性开关与自定义 Bean 覆盖------这就是自定义 starter 的核心

相关推荐
知守观1 小时前
Spring Boot 2.1 → 3.5 迁移推演:这个 2018 年的项目会炸在哪
java·spring boot
LiuYanG1 小时前
MQTT 客户端反复重连怎么办?Spring Boot 接 EMQX 断线重连踩坑实录
spring boot·物联网
Q26433650232 小时前
【有源码】基于SpringBoot+Vue的博物馆展览与服务一体化平台-java博物馆数字化展品展示与交互平台设计
java·vue.js·spring boot·spring·毕业设计·javaweb·课程设计
专业程序开发源3 小时前
springboot全民健身和饮食健康管理系统29158-计算机课程设计、毕业设计
java·spring boot·后端·python·django·php·课程设计
ym hyd 1113 小时前
汽车零部件缺陷管理系统源码 Java+SpringBoot+Vue3 前后分离
java·vue.js·spring boot·汽车·毕设
paopaokaka_luck4 小时前
高校社团管理(AI辅助任务分配、协同过滤算法推荐、ECharts数据可视化、活动参与闭环、校园交流与反馈、器材借还管理)
java·前端·javascript·spring boot·数据分析·echarts
vx_Biye_Design4 小时前
springboot小区管理系统68491-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·spring·课程设计·express
专业程序开发源4 小时前
springboot外卖系统94294-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·spring·php·课程设计
FYKJ_20104 小时前
springboot心理健康管理系统86254-计算机课程设计、毕业设计
vue.js·spring boot·后端·python·mysql·django·课程设计