✅ 一、Spring Boot 自动装配原理(完整版)
🔍 背后到底发生了什么?
1. @SpringBootApplication
的作用
@SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan
-
@EnableAutoConfiguration
:核心,开启 Spring Boot 自动装配能力 -
@ComponentScan
:自动扫描项目所在包下的 Bean(默认包结构下才生效) -
@Configuration
:声明当前类为配置类
2. 自动装配核心流程图解拆解:
步骤 | 机制 | 实现类 |
---|---|---|
1 | 启动类上 @EnableAutoConfiguration | 声明了自动配置入口 |
2 | 导入 AutoConfigurationImportSelector | @Import 注入了该选择器 |
3 | selectImports() 方法执行 | 加载所有自动配置类 |
4 | 从 META-INF/spring.factories 中读取 | key 为 EnableAutoConfiguration 的配置类全限定名 |
5 | 判断是否注入(@ConditionalOnXxx ) | 比如 @ConditionalOnClass , @ConditionalOnMissingBean |
6 | 满足条件 → 自动注入相关 Bean | 自动创建 RedisTemplate、DataSource、RabbitMQ 等 |
📂 例子:
# spring-boot-autoconfigure.jar 中的配置:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
💬 面试模板答法(口语化表达):
Spring Boot 的自动装配依赖于
@EnableAutoConfiguration
,它内部通过AutoConfigurationImportSelector
动态加载所有在spring.factories
文件中配置的自动配置类。这些自动配置类内部又通过一系列@ConditionalXxx
注解判断是否需要注入 Bean。比如你引入了 Redis Starter,它就会自动帮你配置RedisTemplate
,前提是你没有自定义这个 Bean。
✅ 二、Spring 三级缓存机制(用于解决循环依赖)
❓ 为什么需要三级缓存?
为了解决 Bean A 和 Bean B 相互依赖(循环依赖)的问题。Spring 通过分步骤暴露 Bean,确保依赖注入完成。
🧠 缓存结构解析(类:DefaultSingletonBeanRegistry)
缓存级别 | 对应 Map | 含义 |
---|---|---|
一级缓存 | singletonObjects | 完整创建好的单例对象 |
二级缓存 | earlySingletonObjects | 提前暴露的对象,避免循环依赖 |
三级缓存 | singletonFactories | 创建代理对象的工厂(ObjectFactory ) |
🔄 详细执行过程:
假设有两个 Bean:A → B → A
-
Spring 开始创建 A → 将 A 的构造方法生成的 ObjectFactory 放入三级缓存
-
A 还未注入属性,这时 A 被标记为“创建中”
-
Spring 发现 A 依赖 B → 开始创建 B
-
B 发现又依赖 A → 从三级缓存提取 A 的 ObjectFactory → 得到早期 A 实例(可能是代理对象)→ B 顺利完成注入
-
回到 A → 继续完成属性注入和初始化 → 放入一级缓存
-
移除二级缓存与三级缓存的相关引用
🚫 哪些情况不能解决循环依赖?
依赖方式 | 是否支持 | 说明 |
---|---|---|
构造器注入 | ❌ | 因为对象未创建,无法提前暴露引用 |
@Autowired / setter | ✅ | 对象可提前暴露引用 |
多例模式(prototype) | ❌ | Spring 不管理完整生命周期 |
💬 面试模板答法:
Spring 为了解决单例 Bean 的循环依赖问题,引入了三级缓存机制。Bean 创建过程中,Spring 会先将 ObjectFactory 放入三级缓存,如果后续发现依赖项需要提前使用这个 Bean,就通过三级缓存提前暴露一个半成品引用(可能是代理),避免死循环。创建完成后,Bean 会转移至一级缓存。
🧩 拓展知识点建议(面试常问):
拓展点 | 面试问题 | 回答技巧 |
---|---|---|
Spring Boot 自动装配排查问题 | 如果配置类不生效怎么办? | 检查 spring.factories 和 @Conditional 是否匹配当前环境 |
三级缓存源码入口 | 是哪个类处理的缓存机制? | DefaultSingletonBeanRegistry 是三级缓存的具体实现类 |
禁止自动配置 | 如何排除某个自动配置类? | 使用 @SpringBootApplication(exclude = {RedisAutoConfiguration.class}) |
循环依赖调试 | 如何模拟和测试? | 使用 @Autowired 注入两个互相依赖的 Bean 并打印创建过程 |
🗂️ 总结记忆模板表格(可打印)
模块 | 内容 | 类/注解 | 用途 |
---|---|---|---|
自动装配机制 | @SpringBootApplication = 三合一 | @EnableAutoConfiguration | 启动自动配置 |
配置加载来源 | spring.factories | AutoConfigurationImportSelector | 加载所有自动配置类 |
条件判断装配 | @ConditionalOnXxx | RedisAutoConfiguration、WebMvcAutoConfiguration 等 | 按需注入 Bean |
三级缓存机制 | singletonObjects / earlySingletonObjects / singletonFactories | DefaultSingletonBeanRegistry | 解决循环依赖 |