Spring Boot 自动配置原理
候选人小赵在字节跳动面试,面到 Spring Boot 部分时,面试官问了一个看似常规的问题:
"Spring Boot 的自动配置是怎么实现的?"
小赵张嘴就来:"就是 Spring Boot 会自动扫描 classpath 下的配置类,然后根据条件注解来决定要不要生效。"面试官点点头,追问:"那它是怎么扫描到这些配置类的?扫描的是哪个文件?"
小赵愣了一下:"好像是 spring.factories?"面试官继续:"那 Spring Boot 2.7 和 3.x 版本有什么区别?"小赵彻底卡住了。
【面试官心理】
这道题我通常用来试探候选人对 Spring Boot "约定大于配置"这个核心理念的理解程度。能背出 spring.factories 的占 60%,能说出 AutoConfigurationImportSelector 工作流程的占 30%,能讲清楚 Spring Boot 3.x 变化的只有 10%。这道题能答到最后的,基本都在 Spring Boot 上踩过不少坑。
一、自动配置的核心入口 🔴
1.1 从 @SpringBootApplication 说起
一切要从 @SpringBootApplication 这个注解说起。它的底层组合了三个关键注解:
其中 @EnableAutoConfiguration 才是自动配置的真正入口。这个注解通过 @Import 导入了一个关键类:
1.2 AutoConfigurationImportSelector 的加载流程
AutoConfigurationImportSelector 实现了 DeferredImportSelector 接口,它的核心方法 selectImports() 调用了 getCandidateConfigurations():
这里 SpringFactoriesLoader.loadFactoryNames() 会去 classpath 下寻找 META-INF/spring.factories 文件,读取其中 org.springframework.boot.autoconfigure.EnableAutoConfiguration 键对应的所有自动配置类全限定名。
Spring Boot 2.7 之前,所有自动配置类都在 spring.factories 的 EnableAutoConfiguration 键下列出。这个文件可能有几千行,面试时说"我看过 spring.factories"的人,十有八九只是瞟了一眼。
1.3 Spring Boot 2.7+ 的重大变化
2022 年 Spring Boot 2.7 引入了 AutoConfiguration.imports 文件,彻底改变了自动配置的加载方式:
Spring Boot 3.x 完全移除了 spring.factories,统一使用 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。
核心区别:
面试时如果能主动提到 Spring Boot 3.x 的变化,面试官会高看你一眼。这意味着你不只是会用,还关注框架演进。
二、条件注解体系 🟡
2.1 @Conditional 系列注解
光扫描到配置类还不够,Spring Boot 还需要根据条件决定这些配置类是否生效。这套机制靠的是 @Conditional 系列注解:
以 DataSourceAutoConfiguration 为例:
2.2 配置类的执行顺序
如果多个自动配置类有依赖关系,Spring Boot 提供了控制顺序的注解:
📖 点击展开 Spring Boot 自动配置完整流程图
三、❌ 错误示范
3.1 背题型翻车
候选人原话:"Spring Boot 的自动配置就是通过 spring.factories 文件实现的,会自动扫描配置类然后注册 bean。"
问题诊断:
- 只知道 spring.factories,不知道 AutoConfiguration.imports 的存在
- 把"加载"和"生效"混为一谈——加载不等于生效,还需要 @Conditional 判断
- 完全不知道 Spring Boot 3.x 的变化
面试官内心 OS:"这个候选人只是在背题,没实际研究过源码。Spring Boot 3.x 都发布两年了,还在死磕 spring.factories。"
3.2 混淆概念型
候选人原话:"@ComponentScan 和 @EnableAutoConfiguration 是一样的,都会扫描 Bean。"
问题诊断:
- 完全不理解两个注解的本质区别:
@ComponentScan扫描的是加了@Component及其派生注解的类,而@EnableAutoConfiguration扫描的是spring.factories/AutoConfiguration.imports中声明的@Configuration类 - 不知道
@ComponentScan默认扫描当前包及子包
3.3 知其然不知其所以然
候选人原话:"@ConditionalOnClass 就是检查类存不存在,存在就加载。"
问题诊断:
- 知道有条件判断,但不知道
@ConditionalOnClass的底层实现原理——它是通过 ASM 动态检查字节码,而不是真正加载类 - 不知道"检查类存在"是为了避免 ClassNotFoundException 的连锁反应
【面试官心理】
这三种错误我在面试中见过太多次。第一种是纯背书,第二种是概念混乱,第三种是只知表面。我通常会在候选人说完后追问三个问题:1. "那自动配置类的加载顺序怎么控制?" 2. "Spring Boot 3.x 改了什么?" 3. "@ConditionalOnMissingBean 和 @ConditionalOnBean 有什么区别?"能答出两个以上的,基本都有实战经验。
四、标准回答 🟢
4.1 P5 级别:能说清楚基本流程
"Spring Boot 的自动配置核心靠 @EnableAutoConfiguration 注解触发,它通过 @Import 导入了 AutoConfigurationImportSelector。这个类会在启动时调用 SpringFactoriesLoader.loadFactoryNames(),去 classpath 下的 META-INF/spring.factories 文件中读取 EnableAutoConfiguration 键对应的所有自动配置类。然后根据 @Conditional 系列条件注解过滤,最终注册符合条件的配置类到容器中。"
4.2 P6 级别:能说出版本差异和源码细节
"自动配置的核心链路是:SpringApplication.run → @EnableAutoConfiguration → AutoConfigurationImportSelector.getCandidateConfigurations() → SpringFactoriesLoader.loadFactoryNames()。
Spring Boot 2.7 之前使用 META-INF/spring.factories,格式是键值对;2.7 引入了 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,每个配置类占一行;3.x 完全移除了 spring.factories。
配置类加载后不会立即生效,而是经过 @Conditional 系列条件注解的过滤——比如 @ConditionalOnClass 检查字节码中是否存在目标类,@ConditionalOnProperty 检查配置属性,@ConditionalOnMissingBean 检查容器中是否已存在该 Bean。执行顺序通过 @AutoConfigureBefore/After/Order 控制。"
4.3 P7 级别:能讲清楚设计意图和生产实践
"这道题背后其实考的是 Spring Boot '约定大于配置' 的核心理念。自动配置的本质是:框架作者预先写好了一堆配置类,用户只需要引入 starter 依赖、修改少量配置,就能开箱即用。
我之前在项目里排查过一个坑:项目引入了 Redis starter,但由于我们自定义了 RedisTemplate,导致自动配置的 RedisAutoConfiguration 被跳过了。后来定位到是 @ConditionalOnMissingBean 在起作用——如果用户已经注册了某个类型的 Bean,框架就不会再自动配置它。
Spring Boot 3.x 的变化也值得关注:从 spring.factories 迁移到 imports 文件,本质上是把扫描范围从整个 classpath 收敛到 starter 自己的 jar 包内,避免类和配置的相互污染。同时 3.x 引入了 @AutoConfiguration 注解替代普通 @Configuration,进一步区分了自动配置类和用户自定义配置类。"
五、生产避坑
5.1 踩过的真实坑
场景:我们在升级 Spring Boot 2.4 到 2.7 时,发现某个自定义的自动配置类突然不生效了。排查了半天,发现是 Spring Boot 2.7 改了 spring.factories 的加载优先级——AutoConfiguration.imports 文件中的配置优先于 spring.factories。
根因:spring.factories 是全局扫描,而 AutoConfiguration.imports 是每个 starter 自己管理。我们自定义 starter 的 spring.factories 被 Spring Boot 自己的 spring-boot-autoconfigure 包的配置覆盖了。
解法:把配置迁移到 imports 文件,或者使用 @AutoConfiguration 注解。
5.2 排查工具
开启 debug 模式后,Spring Boot 会输出一个 AutoConfiguration report,显示哪些自动配置类通过了条件检查,哪些被跳过了,跳过的原因是什么。
生产环境强烈建议开启 debug 模式排查一次,把生效的自动配置都过一遍。这样你才能知道项目到底依赖了哪些框架特性,避免引入无用的 starter 增大包体积。