海妖大陆手游Kraken Land
83.46MB · 2025-10-19
一句话总结:
Spring 只解决「单例 Bean 的字段 / setter 循环依赖」,靠的是三级缓存 + 提前暴露“半成品”引用;构造器注入、原型作用域的循环依赖直接抛异常。
下面把完整机制拆开讲清:
依赖方式 | 作用域 | Spring 能否解决 | 原因 |
---|---|---|---|
字段 / setter 注入 | singleton | 三级缓存可提前暴露对象引用 | |
构造器注入 | singleton | 实例化阶段就卡住,无法提前暴露 | |
任何方式 | prototype | 原型 Bean 不缓存,每次新建,无法复用引用 |
位置:DefaultSingletonBeanRegistry
缓存 | 变量 | 内容 | 生命周期阶段 |
---|---|---|---|
一级 singletonObjects | ConcurrentHashMap | 完全初始化好的单例 | 就绪可用 |
二级 earlySingletonObjects | ConcurrentHashMap | 提前曝光的“裸”对象(可能代理) | 已实例化,未填充属性 |
三级 singletonFactories | HashMap<String, ObjectFactory<?>> | 能生成早期引用的 ObjectFactory | 实例化后马上放进去 |
以「A → B,B → A」字段注入为例:
getBean(A)
ObjectFactory
并放入三级缓存getBean(B)
getBean(B)
ObjectFactory
放入三级缓存getBean(A)
此时 A 还在三级缓存,调用 ObjectFactory.getObject()
拿到早期引用(若需要 AOP 则在这里生成代理),把结果放进二级缓存并删除三级缓存条目;B 拿到这个引用完成属性填充,初始化结束 → 放入一级缓存
B 返回后,A 继续完成属性填充 → 初始化结束 → 放入一级缓存
整个过程没有两次初始化,也不会出现不完整对象被外部拿到
构造器注入时,实例化阶段就必须把依赖传进去;
此时 Spring 还没机会把“半成品”放进任何缓存,
于是出现「A 等 B,B 等 A」的死锁,直接抛:
BeanCurrentlyInCreationException
原型 Bean 每次 getBean
都新建对象,不缓存;
无法复用同一个引用,因此无法通过“提前暴露”打破循环。
单例 + 字段 / setter + 三级缓存 = 可解;
构造器 or 原型 = 无解。
Spring通过三级缓存机制来解决单例Bean的循环依赖问题。下面详细讲解其工作原理。
Spring在DefaultSingletonBeanRegistry
类中维护了三个缓存级别:
// 第一级缓存:存放完全初始化好的Bean(成品)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 第二级缓存:存放早期的Bean引用(半成品)
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
// 第三级缓存:存放Bean工厂,用于创建早期引用
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
以A依赖B,B依赖A为例:
// 1. 开始创建A,标记A为"创建中"
beforeSingletonCreation("A");
// 2. 实例化A(调用构造函数),此时A对象已存在但属性为null
instance = createBeanInstance("A");
// 3. 将A的ObjectFactory放入三级缓存
addSingletonFactory("A", () -> getEarlyBeanReference("A", mbd, instance));
此时三级缓存中有了A的工厂,可以生产A的早期引用。
// 4. 填充A的属性
populateBean("A", mbd, instanceWrapper);
// 发现需要注入B,开始获取Bean B
// 5. 开始创建B
beforeSingletonCreation("B");
// 6. 实例化B
instance = createBeanInstance("B");
// 7. 将B的ObjectFactory放入三级缓存
addSingletonFactory("B", () -> getEarlyBeanReference("B", mbd, instance));
// 8. 填充B的属性,发现需要注入A
// 开始获取Bean A的流程:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 第一级缓存查找(成品)
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 第二级缓存查找(半成品)
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// 第三级缓存查找(工厂)
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 调用工厂获取早期引用
singletonObject = singletonFactory.getObject();
// 将A从三级缓存升级到二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
// 9. 将A的早期引用注入到B中
// 10. 完成B的初始化
initializeBean("B", exposedObject, mbd);
// 11. 将B放入一级缓存
addSingleton("B", singletonObject);
// 12. 回到A的创建流程,现在可以获取到完整的B
// 13. 将B注入到A中
// 14. 完成A的初始化
initializeBean("A", exposedObject, mbd);
// 15. 将A放入一级缓存
addSingleton("A", singletonObject);
这个方法负责处理AOP代理:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
// 如果需要代理,这里会返回代理对象
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
// 放入一级缓存
this.singletonObjects.put(beanName, singletonObject);
// 从二、三级缓存移除
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
graph TD
A[开始创建A] --> B[实例化A]
B --> C[将A工厂放入三级缓存]
C --> D[填充A属性发现依赖B]
D --> E[开始创建B]
E --> F[实例化B]
F --> G[将B工厂放入三级缓存]
G --> H[填充B属性发现依赖A]
H --> I[从缓存获取A]
I --> J{三级缓存查找}
J --> K[找到A工厂]
K --> L[创建A早期引用]
L --> M[A放入二级缓存]
M --> N[A注入到B]
N --> O[完成B初始化]
O --> P[B放入一级缓存]
P --> Q[回到A创建流程]
Q --> R[B注入到A]
R --> S[完成A初始化]
S --> T[A放入一级缓存]
缓存级别 | 名称 | 内容 | 作用 |
---|---|---|---|
一级缓存 | singletonObjects | 完整的Bean | 提供最终可用的Bean |
二级缓存 | earlySingletonObjects | 早期Bean引用 | 避免重复创建早期引用 |
三级缓存 | singletonFactories | Bean工厂 | 处理AOP代理,按需创建代理对象 |
@Component
public class A {
private B b;
@Autowired
public A(B b) { // 构造器循环依赖无法解决
this.b = b;
}
}
Spring通过三级缓存机制优雅地解决了循环依赖问题:
这种设计既解决了循环依赖,又保持了Spring AOP的正常工作,是Spring框架中非常精妙的设计之一。
Spring 如何解决循环依赖
1. 循环依赖的类型
1.1 常见的循环依赖场景
// 场景1:相互依赖
@Component
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
@Component
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
// 场景2:三组件循环依赖
@Component
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
@Component
public class ServiceB {
@Autowired
private ServiceC serviceC;
}
@Component
public class ServiceC {
@Autowired
private ServiceA serviceA;
}
// 场景3:自我依赖(少见但可能)
@Component
public class SelfDependent {
@Autowired
private SelfDependent self;
}
2. Spring 的解决方案
2.1 三级缓存机制
Spring 通过三级缓存 + 提前暴露引用的方式解决循环依赖:
// Spring 内部的三级缓存结构
public class DefaultSingletonBeanRegistry {
// 第一级缓存:完整Bean(已初始化完成)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 第二级缓存:早期Bean(已实例化但未初始化)
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
// 第三级缓存:Bean工厂(用于创建早期引用)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// 正在创建中的Bean
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}
2.2 详细解决流程
// 以 A → B → A 为例的详细流程
@Component
public class A {
@Autowired
private B b;
private String name = "A";
public void init() {
System.out.println("A initialized");
}
}
@Component
public class B {
@Autowired
private A a;
private String name = "B";
public void init() {
System.out.println("B initialized");
}
}
解决步骤:
// 步骤1:开始创建A
1. 调用 getBean("A")
2. 标记 A 正在创建:singletonsCurrentlyInCreation.add("A")
3. 实例化 A 对象(此时A是原始对象,b=null,未调用init方法)
// 步骤2:提前暴露A的引用
4. 将A的ObjectFactory放入三级缓存:
singletonFactories.put("A", () -> getEarlyBeanReference("A", mbd, aInstance))
// 步骤3:填充A的属性(发现依赖B)
5. 调用 populateBean("A"),发现需要注入B
6. 调用 getBean("B")
// 步骤4:开始创建B
7. 标记 B 正在创建:singletonsCurrentlyInCreation.add("B")
8. 实例化 B 对象
9. 将B的ObjectFactory放入三级缓存
// 步骤5:填充B的属性(发现依赖A)
10. 调用 populateBean("B"),发现需要注入A
11. 调用 getBean("A")
// 步骤6:获取A的早期引用
12. 发现A正在创建中
13. 从三级缓存获取A的ObjectFactory
14. 调用 factory.getObject() 获取A的早期引用
15. 将A从三级缓存移到二级缓存:earlySingletonObjects.put("A", aEarlyReference)
16. 返回A的早期引用给B
// 步骤7:完成B的创建
17. B持有A的早期引用,完成属性注入
18. 初始化B(调用@PostConstruct、init方法等)
19. 将B放入一级缓存,清理二三级缓存
// 步骤8:完成A的创建
20. A获得完整的B实例,完成属性注入
21. 初始化A
22. 将A放入一级缓存,清理二三级缓存
3. 源码实现解析
3.1 核心方法:doCreateBean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
// 1. 实例化Bean
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
Object bean = instanceWrapper.getWrappedInstance();
// 2. 提前暴露引用(解决循环依赖的关键)
if (earlySingletonExposure) {
// 将Bean工厂添加到三级缓存
addSingletonFactory(beanName,
() -> getEarlyBeanReference(beanName, mbd, bean));
}
// 3. 属性注入(可能触发循环依赖)
populateBean(beanName, mbd, instanceWrapper);
// 4. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
return exposedObject;
}
3.2 核心方法:getSingleton
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1. 从一级缓存查找
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 2. 从二级缓存查找
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 3. 从三级缓存获取ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 4. 创建早期引用
singletonObject = singletonFactory.getObject();
// 5. 移动到二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
3.3 核心方法:addSingletonFactory
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
// 放入三级缓存
this.singletonFactories.put(beanName, singletonFactory);
// 清理二级缓存(确保数据一致性)
this.earlySingletonObjects.remove(beanName);
}
}
}
4. AOP 代理的处理
4.1 代理对象的循环依赖
@Component
public class TransactionalService {
@Autowired
private AnotherService anotherService;
@Transactional
public void doSomething() {
// 事务方法
}
}
@Component
public class AnotherService {
@Autowired
private TransactionalService transactionalService; // 需要代理对象
}
Spring 的处理方式:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
// AbstractAutoProxyCreator 在这里创建代理对象
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
5. 无法解决的循环依赖场景
5.1 构造器注入循环依赖
@Component
public class ConstructorA {
private final ConstructorB b;
@Autowired
public ConstructorA(ConstructorB b) { // 构造器注入
this.b = b;
}
}
@Component
public class ConstructorB {
private final ConstructorA a;
@Autowired
public ConstructorB(ConstructorA a) { // 构造器注入
this.a = a;
}
}
错误信息:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| constructorA defined in file [...]
↑ ↓
| constructorB defined in file [...]
└─────┘
5.2 原型作用域的循环依赖
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeA {
@Autowired
private PrototypeB b;
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeB {
@Autowired
private PrototypeA a;
}
原因:原型 Bean 不缓存,每次都会创建新实例。
5.3 @Async 方法的循环依赖
@Component
public class AsyncService {
@Autowired
private AnotherService anotherService;
@Async
public void asyncMethod() {
// 异步方法
}
}
@Component
public class AnotherService {
@Autowired
private AsyncService asyncService; // 需要代理对象
}
6. 解决方案和最佳实践
6.1 避免循环依赖的设计
// 方案1:使用接口分离
public interface IServiceA {
void methodA();
}
public interface IServiceB {
void methodB();
}
@Component
public class ServiceA implements IServiceA {
@Autowired
private IServiceB serviceB;
}
@Component
public class ServiceB implements IServiceB {
@Autowired
private IServiceA serviceA;
}
// 方案2:使用 setter 注入替代字段注入
@Component
public class SetterA {
private SetterB b;
@Autowired
public void setB(SetterB b) {
this.b = b;
}
}
// 方案3:使用 @Lazy 延迟加载
@Component
public class LazyA {
@Lazy
@Autowired
private LazyB b;
}
6.2 应用启动时检测
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
// 开启循环依赖检测(默认就是true)
app.setAllowCircularReferences(true);
app.run(args);
}
}
7. 调试和排查技巧
7.1 启用调试日志
########## application.properties
logging.level.org.springframework.beans.factory=DEBUG
logging.level.org.springframework.context=DEBUG
########## 或者查看具体的循环依赖信息
spring.main.allow-circular-references=false
########## 强制检测
7.2 使用 BeanPostProcessor 调试
@Component
public class CircularDependencyDebugProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("Bean initialized: " + beanName + " - " + bean.getClass().getSimpleName());
return bean;
}
}
8. 总结
Spring 通过三级缓存机制优雅地解决了循环依赖问题:
最佳实践:
Spring 如何解决循环依赖
1. 循环依赖的类型
1.1 构造器循环依赖(无法解决)
@Service
public class AService {
private final BService bService;
public AService(BService bService) { // 构造器注入
this.bService = bService;
}
}
@Service
public class BService {
private final AService aService;
public BService(AService aService) { // 构造器注入
this.aService = aService;
}
}
结果:Spring 会抛出 BeanCurrentlyInCreationException
1.2 Setter/Field 循环依赖(可以解决)
@Service
public class AService {
@Autowired
private BService bService; // 字段注入
}
@Service
public class BService {
@Autowired
private AService aService; // 字段注入
}
2. 三级缓存机制
Spring 通过三级缓存来解决 Setter/Field 循环依赖:
2.1 三级缓存结构
public class DefaultSingletonBeanRegistry {
// 一级缓存:完整的 Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存:早期的 Bean(已实例化但未完成属性注入)
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
// 三级缓存:ObjectFactory 缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
}
3. 详细解决流程
3.1 AService 和 BService 创建过程
// 步骤1:开始创建 AService
1. getBean("aService") → createBean("aService")
2. doCreateBean("aService"):
- 实例化 AService 对象(调用构造函数)
- 将 AService 包装成 ObjectFactory 放入三级缓存
- 代码:addSingletonFactory("aService", () -> getEarlyBeanReference(...))
// 此时缓存状态:
// 一级缓存:{}
// 二级缓存:{}
// 三级缓存:{"aService": ObjectFactory}
// 步骤2:填充 AService 属性
3. populateBean("aService") → 发现需要 bService
4. getBean("bService") → createBean("bService")
// 步骤3:开始创建 BService
5. doCreateBean("bService"):
- 实例化 BService 对象
- 将 BService 包装成 ObjectFactory 放入三级缓存
// 此时缓存状态:
// 一级缓存:{}
// 二级缓存:{}
// 三级缓存:{"aService": ObjectFactory, "bService": ObjectFactory}
// 步骤4:填充 BService 属性
6. populateBean("bService") → 发现需要 aService
7. getBean("aService") → getSingleton("aService")
// 关键步骤:获取 AService 的早期引用
8. getSingleton("aService") 执行过程:
- 一级缓存:未找到
- 二级缓存:未找到
- 三级缓存:找到 ObjectFactory
- 调用 objectFactory.getObject() 获取 AService 早期引用
- 将 AService 从三级缓存升级到二级缓存
// 此时缓存状态:
// 一级缓存:{}
// 二级缓存:{"aService": AService@早期引用}
// 三级缓存:{"bService": ObjectFactory}
// 步骤5:继续 BService 创建
9. 将 AService 早期引用注入到 BService
10. BService 完成初始化,放入一级缓存
// 此时缓存状态:
// 一级缓存:{"bService": BService@完整对象}
// 二级缓存:{"aService": AService@早期引用}
// 三级缓存:{}
// 步骤6:继续 AService 创建
11. 将完整的 BService 注入到 AService
12. AService 完成初始化,放入一级缓存
// 最终缓存状态:
// 一级缓存:{"aService": AService@完整对象, "bService": BService@完整对象}
// 二级缓存:{}
// 三级缓存:{}
3.2 核心源码解析
// 获取单例 Bean 的核心方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1. 从一级缓存查找完整 Bean
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 2. 从二级缓存查找早期 Bean
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 3. 从三级缓存获取 ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 创建早期引用(可能返回代理对象)
singletonObject = singletonFactory.getObject();
// 升级到二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
// 添加 ObjectFactory 到三级缓存
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
}
}
}
4. AOP 代理的特殊处理
4.1 为什么需要三级缓存?
// ObjectFactory 的创建
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
// 如果 Bean 需要代理,这里会返回代理对象
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
关键点:
5. 无法解决的循环依赖场景
5.1 构造器注入
@Component
public class CircularA {
private final CircularB circularB;
public CircularA(CircularB circularB) { // 构造器注入
this.circularB = circularB;
}
}
@Component
public class CircularB {
private final CircularA circularA;
public CircularB(CircularA circularA) { // 构造器注入
this.circularA = circularA;
}
}
原因:Bean 在实例化阶段就需要依赖对象,但此时 Bean 还未创建,无法放入三级缓存。
5.2 原型作用域的 Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeA {
@Autowired
private PrototypeB prototypeB;
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeB {
@Autowired
private PrototypeA prototypeA;
}
原因:原型 Bean 不会放入缓存,每次都会创建新实例。
5.3 @Async 方法的循环依赖
@Service
public class AsyncServiceA {
@Autowired
private AsyncServiceB serviceB;
@Async
public void asyncMethod() {
// 异步方法
}
}
@Service
public class AsyncServiceB {
@Autowired
private AsyncServiceA serviceA;
}
原因:@Async 会创建代理对象,可能在某些情况下导致循环依赖解决失败。
6. 解决方案和最佳实践
6.1 避免循环依赖的设计
// 好的设计:使用接口解耦
public interface UserService {
User findUser(Long id);
}
public interface OrderService {
Order findOrder(Long id);
}
@Service
public class UserServiceImpl implements UserService {
// 不直接依赖具体实现
@Autowired
private OrderService orderService;
}
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private UserService userService;
}
6.2 使用 @Lazy 注解
@Service
public class ServiceA {
@Lazy // 延迟注入
@Autowired
private ServiceB serviceB;
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
6.3 使用 setter 注入
@Service
public class ServiceA {
private ServiceB serviceB;
@Autowired
public void setServiceB(ServiceB serviceB) { // setter 注入
this.serviceB = serviceB;
}
}
6.4 使用 ApplicationContextAware
@Service
public class ServiceA implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void doSomething() {
// 在需要的时候再获取 Bean
ServiceB serviceB = applicationContext.getBean(ServiceB.class);
}
}
7. 调试技巧
7.1 查看循环依赖信息
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
private ApplicationContext applicationContext;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) {
// 检查是否存在循环依赖
if (applicationContext instanceof ConfigurableApplicationContext) {
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)
((ConfigurableApplicationContext) applicationContext).getBeanFactory();
// 查看正在创建的 Bean
Set<String> singletonsInCreation = beanFactory.getSingletonsCurrentlyInCreation();
System.out.println("正在创建的Bean: " + singletonsInCreation);
}
}
}
8. 总结
Spring 通过三级缓存机制优雅地解决了单例 Bean 的字段/Setter 注入循环依赖问题:
三级缓存分工:
解决时机:在 Bean 实例化后、属性注入前暴露引用
限制条件:
最佳实践:
理解 Spring 的循环依赖解决机制,有助于我们设计更健壮的应用程序架构。
Spring 如何解决循环依赖
什么是循环依赖
循环依赖是指两个或多个 Bean 相互依赖,形成闭环:
// 情况1:直接相互依赖
@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private A a;
}
// 情况2:间接循环依赖
@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private C c;
}
@Component
public class C {
@Autowired
private A a;
}
Spring 的解决方案
核心机制:三级缓存
Spring 通过三级缓存机制解决循环依赖问题:
public class DefaultSingletonBeanRegistry {
// 一级缓存:完整Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存:早期Bean
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
// 三级缓存:ObjectFactory
private final Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>(16);
}
解决流程详解
场景:A ↔ B 相互依赖
步骤1:开始创建 A
// 1. 调用 getBean("A")
// 2. 标记 A 正在创建中
beforeSingletonCreation("A");
// 3. 实例化 A(调用构造方法)
Object A = createBeanInstance("A");
// 4. 将 A 的 ObjectFactory 放入三级缓存
addSingletonFactory("A", () -> getEarlyBeanReference("A", mbd, A));
// 5. 开始属性注入,发现需要 B
populateBean("A");
步骤2:A 需要 B,开始创建 B
// 1. 调用 getBean("B")
// 2. 标记 B 正在创建中
beforeSingletonCreation("B");
// 3. 实例化 B(调用构造方法)
Object B = createBeanInstance("B");
// 4. 将 B 的 ObjectFactory 放入三级缓存
addSingletonFactory("B", () -> getEarlyBeanReference("B", mbd, B));
// 5. 开始属性注入,发现需要 A
populateBean("B");
步骤3:B 获取 A 的早期引用
// B 在 populateBean 时调用 getBean("A")
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 第一次查找:一级缓存(没有A,因为A还没创建完成)
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 第二次查找:二级缓存(没有A)
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 第三次查找:三级缓存(找到A的ObjectFactory)
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 通过ObjectFactory获取A的早期引用
singletonObject = singletonFactory.getObject();
// 将A从三级缓存移动到二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
步骤4:B 完成创建
// B 获取到 A 的早期引用后,完成属性注入
// 然后完成 B 的初始化(@PostConstruct, InitializingBean等)
// 最后将 B 放入一级缓存
addSingleton("B", B);
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
}
}
步骤5:A 完成创建
// A 继续属性注入,现在可以获取到完整的 B
// 完成 A 的初始化
// 将 A 放入一级缓存
addSingleton("A", A);
源码实现细节
关键方法解析
doCreateBean 方法
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
// 1. 实例化
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
Object bean = instanceWrapper.getWrappedInstance();
// 2. 判断是否支持早期暴露
boolean earlySingletonExposure = (mbd.isSingleton() &&
this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 3. 添加到三级缓存(关键步骤!)
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 4. 属性注入(可能触发循环依赖)
Object exposedObject = bean;
populateBean(beanName, mbd, instanceWrapper);
// 5. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
// 6. 处理早期引用
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
}
}
return exposedObject;
}
addSingletonFactory 方法
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
// 放入三级缓存
this.singletonFactories.put(beanName, singletonFactory);
// 清除二级缓存
this.earlySingletonObjects.remove(beanName);
}
}
}
特殊情况处理
1. 有 AOP 代理的情况
@Component
public class A {
@Autowired
private B b;
public void businessMethod() {
// 业务逻辑
}
}
@Aspect
@Component
public class MyAspect {
@Before("execution(* A.businessMethod(..))")
public void beforeAdvice() {
System.out.println("Before method execution");
}
}
处理机制:
getEarlyBeanReference
方法中会调用 AOP 相关的后处理器protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
// AOP 在这里创建代理对象
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
2. @Async 方法的情况
@Component
public class A {
@Autowired
private B b;
@Async
public void asyncMethod() {
// 异步方法
}
}
@Component
public class B {
@Autowired
private A a;
}
处理:同样通过 getEarlyBeanReference
方法创建代理
无法解决的循环依赖场景
1. 构造器注入的循环依赖
@Component
public class A {
private B b;
@Autowired
public A(B b) { // 构造器注入
this.b = b;
}
}
@Component
public class B {
private A a;
@Autowired
public B(A a) { // 构造器注入
this.a = a;
}
}
原因:在构造器阶段就需要完整的依赖对象,此时 Bean 还未实例化,无法放入三级缓存。
错误信息:
BeanCurrentlyInCreationException: Error creating bean with name 'A':
Requested bean is currently in creation: Is there an unresolvable circular reference?
2. 原型作用域的循环依赖
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeA {
@Autowired
private PrototypeB b;
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeB {
@Autowired
private PrototypeA a;
}
原因:原型 Bean 不缓存,每次都会创建新实例。
3. @Configuration 类的循环依赖
@Configuration
public class ConfigA {
@Autowired
private ConfigB configB;
}
@Configuration
public class ConfigB {
@Autowired
private ConfigA configA;
}
解决方案和最佳实践
1. 代码重构方案
方案1:使用 setter 注入代替构造器注入
@Component
public class A {
private B b;
@Autowired
public void setB(B b) { // setter注入
this.b = b;
}
}
方案2:使用 @Lazy 注解
@Component
public class A {
private final B b;
@Autowired
public A(@Lazy B b) { // 延迟加载
this.b = b;
}
}
方案3:使用 ApplicationContextAware
@Component
public class A implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void someMethod() {
// 在需要的时候再获取B
B b = applicationContext.getBean(B.class);
}
}
方案4:重新设计代码结构
// 提取公共逻辑到第三个类
@Component
public class ServiceFacade {
@Autowired
private A a;
@Autowired
private B b;
public void commonBusiness() {
a.doSomething();
b.doSomething();
}
}
2. Spring 配置方案
开启循环依赖支持(默认开启)
@Configuration
public class AppConfig {
// Spring Boot 2.6+ 默认关闭循环依赖
// 需要手动开启
@Bean
public AbstractBeanFactory abstractBeanFactory() {
return new DefaultListableBeanFactory() {
{
setAllowCircularReferences(true);
}
};
}
}
调试和排查技巧
1. 查看循环依赖信息
@Component
public class CircularDependencyDetector implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
if (applicationContext instanceof ConfigurableApplicationContext) {
ConfigurableListableBeanFactory beanFactory =
((ConfigurableApplicationContext) applicationContext).getBeanFactory();
if (beanFactory instanceof DefaultListableBeanFactory) {
// 可以查看三级缓存状态
System.out.println("检测循环依赖...");
}
}
}
}
2. 使用 Spring Boot Actuator
management:
endpoints:
web:
exposure:
include: beans
endpoint:
beans:
enabled: true
访问:http://localhost:8080/actuator/beans
查看 Bean 依赖关系
总结
Spring 通过三级缓存机制优雅地解决了循环依赖问题:
三级缓存分工明确:
解决条件:
设计思想:
理解 Spring 的循环依赖解决机制,有助于编写更健壮的代码和更好地排查相关问题。
Spring 如何解决循环依赖
1. 循环依赖的定义和类型
1.1 什么是循环依赖 循环依赖是指两个或多个 Bean 相互依赖,形成闭环:
或者更复杂的:
1.2 循环依赖的类型
// 1. 字段注入循环依赖(Spring 可以解决)
@Component
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
@Component
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
// 2. setter 方法注入循环依赖(Spring 可以解决)
@Component
public class ServiceA {
private ServiceB serviceB;
@Autowired
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
// 3. 构造器注入循环依赖(Spring 无法解决)
@Component
public class ServiceA {
private final ServiceB serviceB;
@Autowired
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
2. Spring 解决循环依赖的核心机制
2.1 三级缓存架构
Spring 通过三级缓存解决循环依赖问题:
public class DefaultSingletonBeanRegistry {
// 一级缓存:完整 Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存:早期 Bean(已实例化但未初始化)
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
// 三级缓存:ObjectFactory(用于创建早期引用)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// 正在创建中的 Bean
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}
2.2 解决流程详细分析
示例场景:ServiceA ↔ ServiceB 循环依赖
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
public void methodA() {
System.out.println("ServiceA method");
}
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
public void methodB() {
System.out.println("ServiceB method");
}
}
解决步骤:
开始创建 ServiceA
// 标记 A 正在创建
singletonsCurrentlyInCreation.add("serviceA");
// 实例化 ServiceA(调用构造函数)
ServiceA a = new ServiceA();
// 将 ServiceA 的 ObjectFactory 放入三级缓存
addSingletonFactory("serviceA", () -> getEarlyBeanReference("serviceA", mbd, a));
ServiceA 属性注入,发现需要 ServiceB
// 在 populateBean 阶段,发现 @Autowired ServiceB
// 调用 getBean("serviceB") 获取 ServiceB
开始创建 ServiceB
// 标记 B 正在创建
singletonsCurrentlyInCreation.add("serviceB");
// 实例化 ServiceB
ServiceB b = new ServiceB();
// 将 ServiceB 的 ObjectFactory 放入三级缓存
addSingletonFactory("serviceB", () -> getEarlyBeanReference("serviceB", mbd, b));
ServiceB 属性注入,发现需要 ServiceA
// 调用 getBean("serviceA"),发现 serviceA 正在创建
// 从三级缓存获取 ServiceA 的早期引用
ObjectFactory<?> singletonFactory = this.singletonFactories.get("serviceA");
if (singletonFactory != null) {
// 创建早期引用(可能经过 AOP 处理)
Object earlyReference = singletonFactory.getObject();
// 将早期引用放入二级缓存,移除三级缓存
this.earlySingletonObjects.put("serviceA", earlyReference);
this.singletonFactories.remove("serviceA");
// ServiceB 成功注入 ServiceA 的早期引用
}
ServiceB 完成创建
// ServiceB 完成属性注入、初始化等后续步骤
// 将完整的 ServiceB 放入一级缓存
addSingleton("serviceB", b);
// 清理缓存
this.earlySingletonObjects.remove("serviceB");
this.singletonFactories.remove("serviceB");
ServiceA 完成创建
// ServiceA 继续属性注入(此时 ServiceB 已可用)
// ServiceA 完成初始化
// 将完整的 ServiceA 放入一级缓存
addSingleton("serviceA", a);
// 清理缓存
this.earlySingletonObjects.remove("serviceA");
this.singletonFactories.remove("serviceA");
3. 源码关键方法解析
3.1 getSingleton 方法(核心查找逻辑)
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1. 从一级缓存查找完整 Bean
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 2. 从二级缓存查找早期 Bean
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 3. 从三级缓存获取 ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 创建早期引用
singletonObject = singletonFactory.getObject();
// 升级到二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
3.2 doCreateBean 方法(创建流程)
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
// 1. 实例化
Object beanInstance = createBeanInstance(beanName, mbd, args);
// 2. 判断是否允许早期暴露
boolean earlySingletonExposure = (mbd.isSingleton() &&
this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 3. 添加到三级缓存(解决循环依赖的关键)
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, beanInstance));
}
// 4. 属性注入(可能触发循环依赖)
populateBean(beanName, mbd, instanceWrapper);
// 5. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
return exposedObject;
}
3.3 addSingletonFactory 方法
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
}
}
}
4. 特殊情况处理
4.1 AOP 代理对象的循环依赖
@Service
public class UserService {
@Autowired
private OrderService orderService;
@Transactional
public void createUser() {
// 业务逻辑
}
}
@Service
public class OrderService {
@Autowired
private UserService userService; // 需要的是 UserService 的代理对象
}
处理机制:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
// AbstractAutoProxyCreator 会在这里返回代理对象
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
4.2 多级循环依赖
@Service
public class ServiceA {
@Autowired private ServiceB serviceB;
}
@Service
public class ServiceB {
@Autowired private ServiceC serviceC;
}
@Service
public class ServiceC {
@Autowired private ServiceA serviceA; // 三级循环依赖
}
处理流程:
5. Spring 无法解决的循环依赖场景
5.1 构造器注入循环依赖
@Component
public class CircularA {
private final CircularB circularB;
@Autowired
public CircularA(CircularB circularB) { // 构造器注入
this.circularB = circularB;
}
}
@Component
public class CircularB {
private final CircularA circularA;
@Autowired
public CircularB(CircularA circularA) { // 构造器注入
this.circularA = circularA;
}
}
错误信息:
BeanCurrentlyInCreationException:
Error creating bean with name 'circularA':
Requested bean is currently in creation: Is there an unresolvable circular reference?
原因:构造器注入在实例化阶段就需要完整依赖,此时 Bean 还未放入三级缓存。
5.2 Prototype 作用域的循环依赖
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class PrototypeA {
@Autowired
private PrototypeB prototypeB;
}
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class PrototypeB {
@Autowired
private PrototypeA prototypeA;
}
原因:Prototype Bean 不缓存,每次都会新建,无法通过缓存机制解决循环依赖。
5.3 @Async 方法的循环依赖
@Service
public class AsyncServiceA {
@Autowired
private AsyncServiceB serviceB;
@Async
public void asyncMethod() {
// 异步方法
}
}
@Service
public class AsyncServiceB {
@Autowired
private AsyncServiceA serviceA; // 可能存在问题
}
6. 解决方案和最佳实践
6.1 避免循环依赖的设计
// 好的设计:使用接口解耦
public interface UserValidator {
boolean validate(User user);
}
@Service
public class BasicUserValidator implements UserValidator {
// 不依赖其他业务Service
}
@Service
public class UserService {
@Autowired
private List<UserValidator> validators; // 依赖接口而非具体实现
}
6.2 使用 @Lazy 注解
@Service
public class ServiceA {
@Lazy // 延迟注入,打破循环
@Autowired
private ServiceB serviceB;
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
6.3 使用 setter 注入 + @Autowired(required = false)
@Service
public class ServiceA {
private ServiceB serviceB;
@Autowired(required = false)
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
6.4 使用 ApplicationContextAware
@Service
public class ServiceA implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void doSomething() {
ServiceB serviceB = applicationContext.getBean(ServiceB.class);
// 使用 serviceB
}
}
7. 总结
Spring 通过三级缓存机制优雅地解决了循环依赖问题:
关键点:
设计启示:Spring 的三级缓存体现了"空间换时间"和"关注点分离"的设计思想,通过缓存分层解决了复杂的依赖关系问题。
Spring 通过 三级缓存机制 和 提前暴露对象引用 的方式,优雅地解决了单例 Bean 之间的循环依赖问题。以下是其核心原理和详细流程:
一、循环依赖的场景 当两个或多个 Bean 相互依赖时,会形成循环依赖:
A → B
)B → A
)二、Spring 解决循环依赖的核心机制 Spring 通过 三级缓存 和 提前暴露对象引用 打破循环依赖的死锁:
1. 三级缓存的结构
缓存层级 | 存储内容 | 作用 |
---|---|---|
一级缓存 | SingletonObjects (完全初始化的 Bean) | 存储已完整初始化的单例 Bean,可直接使用。 |
二级缓存 | EarlySingletonObjects (半成品 Bean) | 存储已实例化但未完全初始化的 Bean(属性未注入),用于循环依赖场景。 |
三级缓存 | SingletonFactories (ObjectFactory) | 存储 Bean 的工厂对象,用于生成代理对象或原始对象(解决 AOP 代理问题)。 |
2. 关键流程 以 A → B → A 的循环依赖为例,说明 Spring 的处理步骤:
(1)创建 Bean A
ObjectFactory
存入 三级缓存。(2)创建 Bean B
ObjectFactory
存入 三级缓存。(3)解决 Bean A 的循环依赖
ObjectFactory
,调用 getObject()
生成 半成品 Bean A(可能是代理对象)。(4)完成 Bean B 的初始化
init-method
)。(5)完成 Bean A 的初始化
三、为什么需要三级缓存? 1. 解决 AOP 代理问题
@Transactional
、@Async
),三级缓存的 ObjectFactory
可以按需生成 代理对象 或 原始对象。2. 避免重复创建
ObjectFactory
延迟对象生成,确保单例 Bean 的唯一性。3. 性能优化
四、源码解析
关键方法位于 DefaultSingletonBeanRegistry
类中:
1. 获取单例 Bean( getSingleton )
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1. 从一级缓存获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 2. 从二级缓存获取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 3. 从三级缓存获取工厂对象,生成半成品 Bean
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 升级到二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
2. 添加工厂对象到三级缓存( addSingletonFactory )
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
// 将工厂对象存入三级缓存
this.singletonFactories.put(beanName, singletonFactory);
// 标记 Bean 正在创建中
this.registeredSingletons.add(beanName);
}
}
}
五、限制与注意事项 1. 仅支持单例 Bean
2. 构造器注入的局限性
public A(B b) {}
),三级缓存无法解决,会抛出 BeanCurrentlyInCreationException
。3. 代理对象的兼容性
六、总结
机制 | 作用 |
---|---|
三级缓存 | 分阶段存储 Bean 的不同状态(原始对象、半成品、完全初始化)。 |
提前暴露引用 | 通过三级缓存的工厂对象,在 Bean 初始化完成前暴露其引用,打破循环。 |
AOP 代理支持 | 工厂对象按需生成代理对象,确保代理逻辑正确执行。 |
Spring 的三级缓存机制通过 分阶段缓存 和 延迟对象生成,高效地解决了单例 Bean 的循环依赖问题,同时兼容 AOP 代理场景。理解这一机制有助于优化 Bean 设计,避免不必要的循环依赖。
Spring如何解决循环依赖
Spring通过三级缓存机制来解决循环依赖问题,这是Spring IoC容器的核心设计之一。下面我将详细解释Spring解决循环依赖的原理和流程。
三级缓存的组成
Spring的三级缓存包括:
一级缓存 (singletonObjects)
ConcurrentHashMap
实现二级缓存 (earlySingletonObjects)
HashMap
实现三级缓存 (singletonFactories)
ObjectFactory
函数式接口Map<String, ObjectFactory<?>>
实现解决循环依赖的核心原理
Spring解决循环依赖的关键在于提前暴露未完全创建完毕的Bean,而不是等待Bean完全初始化后再处理依赖。
解决循环依赖的流程(以A依赖B,B依赖A为例)
创建A:
A需要注入B:
B查找A:
B完成初始化:
A继续完成:
为什么需要三级缓存?
重要注意事项
适用范围:
AOP代理处理:
getEarlyBeanReference
方法中,如果有AOP配置,会在此生成代理对象设计建议:
为什么不能用构造器注入解决循环依赖?
构造器注入是在Bean实例化时完成的,而循环依赖需要在实例化后才能解决。当两个Bean都使用构造器注入对方时,Spring无法解决这种循环依赖,会抛出BeanCurrentlyInCreationException
异常。
总结
Spring的三级缓存机制通过"提前暴露半成品Bean"的方式,解决了Setter注入方式下的循环依赖问题。它在Bean创建过程中,将未完全初始化的Bean提前暴露,使依赖方可以获取到这个"半成品",从而打破循环依赖。这种设计保证了Bean创建过程的一致性和正确性,是Spring IoC容器的重要特性。
Spring 主要通过其 三级缓存机制 来解决单例(Singleton)Bean 之间的循环依赖问题。这是 Spring IoC 容器的核心设计之一,确保了在复杂的依赖关系下 Bean 能够被正确创建。
核心前提
Spring 的循环依赖解决方案仅适用于单例(Singleton)作用域的 Bean,并且是通过setter 注入或字段注入形成的循环依赖。对于构造器注入的循环依赖,或者原型(Prototype)作用域的循环依赖,Spring 无法解决,会直接抛出 BeanCurrentlyInCreationException
异常。
最常见的循环依赖场景是两个 Bean 相互依赖:
AService
依赖 BService
BService
依赖 AService
解决方案:三级缓存
Spring 使用三个 Map 结构(即“三级缓存”)来协同工作:
一级缓存 (singletonObjects
):
二级缓存 (earlySingletonObjects
):
三级缓存 (singletonFactories
):
ObjectFactory
)。工作流程详解
以 AService
和 BService
循环依赖为例:
开始创建 AService
AService
。AService
,调用其构造函数,实例化完成。AService
对象已存在,但它的属性(如 bService
)还未注入。暴露 AService
的早期引用
ObjectFactory
(工厂)放入三级缓存。AService
的早期引用。如果 AService
需要 AOP 代理,这个工厂会在这里创建代理对象。注入 AService
的依赖 (BService
)
AService
需要注入 BService
,于是 Spring 开始创建 BService
。BService
经历同样的过程:实例化完成,并将其 ObjectFactory
放入三级缓存。BService
需要注入 AService
(循环点)
BService
注入 AService
时,Spring 查找 AService
。AService
的 ObjectFactory
。getObject()
方法。getEarlyBeanReference()
:
AService
需要代理(如 @Transactional
),则在此刻创建代理对象。AService
实例。AService
的 ObjectFactory
(保证只创建一次)。BService
中。完成 BService
的创建
BService
完成所有属性的注入和初始化回调。BService
放入一级缓存。BService
的相关条目。完成 AService
的创建
AService
的创建流程,此时 BService
已经创建完毕。BService
注入到 AService
中。AService
完成初始化,成为一个完整的 Bean。AService
放入一级缓存。为什么需要三级缓存?二级不够吗?
这是关键所在。如果只有二级缓存,在 AService
实例化后就直接把原始对象放进二级缓存。当 BService
需要时,会拿到这个原始对象。
但如果 AService
是一个需要事务管理的 Service,那么最终容器里应该是一个代理对象。这就导致了不一致:
BService
持有的是 AService
的原始对象。AService
的代理对象。这破坏了单例原则,也使得 AOP 功能失效。
三级缓存的精妙之处在于: 它不直接存放对象,而是存放一个工厂。这个工厂可以在被调用时动态决定返回原始对象还是代理对象。这样,无论是早期注入还是最终使用,所有地方引用的都是同一个最终对象(要么都是原始对象,要么都是代理对象),保证了对象一致性。
总结
Spring 通过 三级缓存 解决单例 Bean 的循环依赖:
ObjectFactory
。这一机制不仅解决了循环依赖,还巧妙地与 AOP 集成,确保了代理对象的一致性,体现了 Spring 设计的高超之处。
Spring解决循环依赖的核心机制是三级缓存,但这一机制仅针对单例Bean的setter注入/字段注入场景。循环依赖指多个Bean之间互相依赖(如A依赖B,B依赖A),若不处理会导致创建过程陷入无限循环。以下是Spring解决循环依赖的具体逻辑:
一、循环依赖的分类与Spring的处理范围 首先明确Spring能解决和不能解决的循环依赖类型:
scope="prototype"
)的循环依赖(每次创建都是新实例,无法缓存);二、核心解决方案:三级缓存的协同工作 Spring通过三级缓存(按“Bean完成度”从高到低)实现单例Bean循环依赖的破解,核心是**“提前暴露未完全初始化的Bean”**,让依赖方先拿到引用,后续再完善Bean。
1. 三级缓存的定义
2. 解决循环依赖的流程(以A依赖B,B依赖A为例) 假设A和B都是单例Bean,且通过setter注入依赖:
步骤1:创建Bean A
步骤2:创建Bean B
步骤3:B获取A的早期实例,打破循环
步骤4:A完成创建
三、为什么需要三级缓存? 核心是为了处理AOP代理场景下的循环依赖:
@Transactional
注解),最终容器中的A是代理对象,而B注入的却是原始A,会导致对象不一致。四、无法解决的循环依赖场景
构造器循环依赖:
若A的构造器依赖B,B的构造器依赖A,由于实例化(构造器调用)是创建Bean的第一步,此时A和B均未实例化,无法生成工厂对象放入三级缓存,因此会直接抛出BeanCurrentlyInCreationException
。
原型Bean循环依赖:
原型Bean的scope
为prototype
,每次获取都会创建新实例,Spring不会缓存原型Bean,因此循环依赖时会无限创建新实例,最终报错。
总结 Spring解决单例Bean循环依赖的核心是三级缓存+提前暴露未完全初始化的Bean:通过三级缓存延迟处理AOP代理,二级缓存暂存早期实例,一级缓存存储最终完整Bean,三者协同打破了“先有鸡还是先有蛋”的循环。但该机制仅适用于单例Bean的setter/字段注入,对构造器注入和原型Bean无效。
Spring通过三级缓存机制高效地解决了单例Bean的循环依赖问题,同时AOP代理的正确性。以下是其核心原理和详细流程:
一、循环依赖的类型
构造器循环依赖
A
的构造器依赖B
,B
的构造器又依赖A
。@Lazy
注解或重构代码避免。属性循环依赖
A
的属性依赖B
,B
的属性又依赖A
。二、三级缓存机制 Spring通过三个缓存层级管理Bean的不同状态,解决属性循环依赖:
缓存层级 | 存储内容 | 作用 |
---|---|---|
一级缓存 | 完全初始化的Bean(SingletonObjects ) | 存储最终可用的Bean,直接返回给调用者。 |
二级缓存 | 半成品Bean(EarlySingletonObjects ) | 存储已实例化但未初始化的Bean,供循环依赖时提前使用。 |
三级缓存 | Bean工厂(SingletonFactories ) | 存储ObjectFactory ,用于动态生成Bean(如处理AOP代理时的原始Bean或代理Bean)。 |
三、解决循环依赖的核心流程
以A
依赖B
,B
依赖A
为例:
1. 创建Bean A
A
,继续创建。A
的原始对象(未注入属性)。addSingletonFactory("A", () -> getEarlyBeanReference("A", beanA, mbd));
getEarlyBeanReference
可能返回代理对象(如AOP场景),确保代理的唯一性。2. 填充A的属性(发现依赖B)
B
,继续创建。B
的原始对象。A
的工厂,调用getObject()
生成A
的早期引用(可能是代理对象)。A
的早期引用从三级缓存移除,并放入二级缓存。B
完成属性注入(使用二级缓存中的A
)。3. 完成B的初始化
init-method
、@PostConstruct
等。B
直接从此缓存返回。4. 完成A的初始化
B
完成属性注入。init-method
、@PostConstruct
等。A
直接从此缓存返回。四、关键代码解析 1. getSingleton 方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1. 从一级缓存获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 2. 从二级缓存获取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 3. 从三级缓存获取工厂并生成早期引用
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 将早期引用从三级缓存移除,并放入二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
return singletonObject;
}
2. addSingletonFactory 方法
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
// 将工厂放入三级缓存
this.singletonFactories.put(beanName, singletonFactory);
// 标记Bean正在创建中
this.registeredSingletons.add(beanName);
}
}
}
五、为什么需要三级缓存?
解决AOP代理问题
@Transactional
),三级缓存的工厂机制确保代理对象在循环依赖中也能正确生成。A
被代理为AProxy
,三级缓存的工厂会返回AProxy
,而非原始A
。避免重复创建
线程安全
ConcurrentHashMap
,二级/三级缓存通过同步块保证多线程环境下的正确性。六、限制与注意事项
仅支持单例Bean
prototype
)Bean无法使用三级缓存,因为每次请求都会创建新实例。构造器注入无效
@Lazy
注解或重构代码解决。依赖顺序敏感
A
依赖B
时,B
不能先初始化完成)。七、总结 Spring通过三级缓存机制高效解决了属性循环依赖问题:
这一设计兼顾了性能、线程安全和AOP兼容性,是Spring框架的核心特性之一。
以下是Spring解决循环依赖的核心方法及技术细节,基于三级缓存机制实现:
一、三级缓存机制(核心解决方案)
一级缓存 singletonObjects
存储完全初始化的单例Bean,可直接使用
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
二级缓存 earlySingletonObjects
️ 存储提前暴露的Bean半成品(已实例化但未完成属性注入)
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
三级缓存 singletonFactories
存储Bean工厂对象(用于生成代理对象)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
二、解决流程(以A→B→A循环依赖为例)
创建Bean A
singletonFactories
创建Bean B
getObject()
生成A的代理对象earlySingletonObjects
,同时移除三级缓存的工厂完成A的注入
singletonObjects
三、关键限制条件
必须都是单例Bean
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
} // 原型模式直接报错
不能全是构造器注入
四、替代解决方案
Setter/字段注入
允许先创建实例再注入依赖,打破实例化死锁
@Lazy注解
@Autowired
public A(@Lazy B b) { ... } // 延迟初始化代理对象
ObjectFactory
@Autowired
private ObjectFactory<B> bFactory;
public void useB() {
B b = bFactory.getObject(); // 按需获取Bean
}
五、典型异常场景
BeanCurrentlyInCreationException:
Requested bean is currently in creation:
Is there an unresolvable circular reference?
️ 触发条件:
@DependsOn
强制指定的循环初始化顺序Spring 解决循环依赖的核心机制是 三级缓存,它通过分层缓存和提前暴露不完全初始化的 Bean 对象,巧妙地打破了循环引用。同时,Spring 也提供了一些注解和编程手段来辅助处理特定场景。下面这张表格汇总了 Spring 三级缓存的核心信息,帮助你快速理解:
缓存层级 | 名称 | 存储内容 | 主要作用 |
---|---|---|---|
一级缓存 | singletonObjects | 完全初始化完成的单例Bean | 提供最终可用的Bean,是正式的“单例池” |
二级缓存 | earlySingletonObjects | 早期暴露的Bean(已实例化,但未完成初始化) | 解决循环依赖,避免多次从工厂创建实例 |
三级缓存 | singletonFactories | 创建Bean的工厂对象 (ObjectFactory ) | 用于延迟创建早期引用,支持AOP代理 |
Spring 解决循环依赖的核心流程,可以概括为 “实例化 -> 提前暴露 -> 依赖注入 -> 完成初始化” 的过程。下面的流程图描绘了这一核心过程:
flowchart TD
A["创建Bean A<br>getBean(a)"] --> B["实例化A<br>(调用构造函数)"]
B --> C[得到A的原始对象]
C --> D["提前暴露A的引用<br>将 ObjectFactory 放入三级缓存"]
D --> E["属性注入:A 依赖 B<br>触发 getBean(b)"]
E --> F["创建Bean B<br>getBean(b)"]
F --> G["实例化B<br>(调用构造函数)"]
G --> H[得到B的原始对象]
H --> I["提前暴露B的引用<br>将 ObjectFactory 放入三级缓存"]
I --> J["属性注入:B 依赖 A<br>触发 getBean(a)"]
J --> K{"再次查找A<br>一级缓存? --> 无<br>二级缓存? --> 无"}
K -- 三级缓存有 --> L["通过ObjectFactory<br>获取A的早期引用"]
L --> M["将A的早期引用放入二级缓存<br>并从三级缓存移除工厂"]
M --> N["B注入A的早期引用成功"]
N --> O["B完成初始化<br>放入一级缓存"]
O --> P["回到A的属性注入流程<br>此时成功获取到完整的B"]
P --> Q["A完成初始化"]
Q --> R["将A放入一级缓存<br>并清理二、三级缓存"]
R --> S["容器中存在<br>完全初始化的A和B"]
️ 辅助解决方案与适用场景
三级缓存是Spring的默认机制,但开发者也可以通过一些方式主动处理或避免循环依赖:
使用 @Lazy
注解
@Lazy
注解通过延迟加载来打破循环。它对构造函数注入尤为有效。
@Service
public class ServiceA {
private ServiceB serviceB;
public ServiceA(@Lazy ServiceB serviceB) { // 此时注入的是代理对象
this.serviceB = serviceB;
}
}
使用 Setter/字段注入替代构造器注入
Spring 默认只能解决单例模式下通过 Setter 方法或字段属性注入(@Autowired
)形成的循环依赖,而无法解决构造器注入导致的循环依赖。因为构造器注入发生在实例化阶段,此时对象都还未创建,无法提前暴露引用。
使用 @PostConstruct
在其中一个 Bean 注入完成后,再通过注解方法设置依赖。
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
// 其他代码...
}
@Service
public class ServiceB {
private ServiceA serviceA;
@Autowired
public void setServiceA(ServiceA serviceA) {
this.serviceA = serviceA;
}
}
实现 ApplicationContextAware
和 InitializingBean
这是一种更手动的方式,让 Bean 主动从 Spring 上下文中获取依赖。
@Service
public class ServiceA implements ApplicationContextAware, InitializingBean {
private ApplicationContext context;
private ServiceB serviceB;
@Override
public void setApplicationContext(ApplicationContext context) {
this.context = context;
}
@Override
public void afterPropertiesSet() {
// 在所有属性设置完成后,再从容器中获取ServiceB
this.serviceB = context.getBean(ServiceB.class);
}
}
️ 注意事项与限制
Spring 的解决方案虽然强大,但并非万能,存在以下限制:
最佳实践 如果条件允许,优先考虑通过代码重构(如提取公共逻辑到第三个类、使用接口分离职责等)来消除循环依赖,这往往是最根本的解决方案。
总结
Spring 主要通过三级缓存机制自动解决单例 Bean 的 setter/字段注入导致的循环依赖,其本质是空间换时间,通过提前暴露对象引用打破循环。
对于无法自动处理的场景(如构造器注入或需要更细粒度控制),可以使用 @Lazy
、@PostConstruct
或实现接口等编程方式辅助解决。
理解这些机制和限制,能帮助你在设计和调试时更有把握。但记住,一个良好架构的系统应尽量避免循环依赖。
Spring 通过 三级缓存机制 和 对象生命周期管理 巧妙解决了单例 Bean 的循环依赖问题,其核心设计兼顾了性能、线程安全和 AOP 代理兼容性。以下是具体实现原理和流程解析:
一、循环依赖的本质与场景 循环依赖指 两个或多个 Bean 相互引用形成闭环,例如:
A → B → A
A 的构造器依赖 B,B 的构造器依赖 A
Spring 仅支持 单例作用域(Singleton) 的循环依赖解决,原型(Prototype)作用域的 Bean 无法处理。
二、三级缓存的核心设计
Spring 的三级缓存定义在 DefaultSingletonBeanRegistry
类中,各层级作用如下:
缓存层级 | 名称 | 存储内容 | 核心作用 |
---|---|---|---|
一级缓存 | singletonObjects | 完全初始化的单例 Bean(包括依赖注入和 AOP 代理完成后的最终实例) | 直接提供可用的最终 Bean,供外部获取 |
二级缓存 | earlySingletonObjects | 实例化但未完成初始化的 Bean(如构造函数执行完成,但属性注入或初始化方法未执行) | 允许其他 Bean 在循环依赖中获取早期引用,打破循环等待 |
三级缓存 | singletonFactories | 存储生成早期引用的 ObjectFactory 对象 | 支持动态生成代理对象(如 AOP 场景),确保不同依赖链获取的代理对象引用一致 |
三、循环依赖的解决流程(以属性注入为例)
以 A → B → A
为例,流程如下:
创建 Bean A
ObjectFactory
存入三级缓存(singletonFactories
),用于后续生成早期引用(可能是代理对象)。创建 Bean B
ObjectFactory
存入三级缓存。解决循环依赖
getObject()
生成 A 的早期引用(可能为代理对象)。earlySingletonObjects
,供 B 注入。完成 A 的初始化
四、关键设计解析 1. 提前暴露半成品对象
ObjectFactory
暴露到三级缓存,允许其他 Bean 获取未完全初始化的对象。2. AOP 代理兼容性
singletonFactories
中的 ObjectFactory
会调用 getEarlyBeanReference()
生成代理对象,确保依赖注入的始终是代理实例。3. 线程安全与性能优化
getSingleton()
方法中,通过 synchronized
和 volatile
保证多线程环境下缓存的正确性。五、构造器注入的循环依赖问题 Spring 无法通过三级缓存解决构造器注入的循环依赖,原因如下:
@Lazy
注解:延迟加载依赖的 Bean,打破循环。
@Service
public class A {
@Autowired
public A(@Lazy B b) { ... }
}
@Scope(proxyMode = TARGET_CLASS)
生成代理类,代理对象持有依赖的引用。
@Service
@Scope(proxyMode = TARGET_CLASS)
public class B { ... }
六、设计意图与最佳实践
核心目标:
开发建议:
@Lazy
:过度使用可能掩盖设计缺陷。总结 Spring 的三级缓存机制通过 分层存储 Bean 的不同生命周期状态,结合动态代理技术,实现了对单例 Bean 循环依赖的高效解决。其设计体现了对性能、灵活性和扩展性的深度权衡,是 Spring IoC 容器的核心优势之一。
Spring 通过其独特的三级缓存机制有效解决了循环依赖问题,以下是核心原理及关键步骤:
一、核心前提与限制条件
仅适用于单例模式:循环依赖的两个 Bean 必须均为单例(singleton
),原型(prototype
)作用域的 Bean 因不存入缓存而无法提前暴露引用[^4^][^5^]。
非构造函数注入:若依赖通过构造函数注入,由于实例化阶段需立即满足依赖关系,无法提前暴露半成品对象,导致死循环[^4^][^5^]。
Setter/Field 注入方式:依赖需通过 Setter 方法或字段注入,允许延迟注入时机[^3^][^4^]。
二、三级缓存机制解析
一级缓存 singletonObjects
二级缓存 earlySingletonObjects
三级缓存 singletonFactories
ObjectFactory
),而非直接存储 Bean[^1^][^4^]。@Transactional
),则通过工厂生成代理而非原始对象[^1^][^4^]。三、解决循环依赖的完整流程
以经典的A→B→A依赖链为例:
实例化与三级缓存注册
ObjectFactory
存入三级缓存[^1^][^4^]。此时暂不放入一/二级缓存。处理依赖 Bean B
ObjectFactory
存入三级缓存[^1^][^4^]。检测到循环依赖
ObjectFactory
,调用其 getObject()
方法生成早期引用[^1^][^4^]。升级缓存层级
earlySingletonObjects
,供 B 完成属性注入[^1^][^4^]。完成初始化并最终放入一级缓存
singletonObjects
[^1^][^4^]。四、关键设计优势
双重延迟决策
状态完整性保障
populateBean()
完成属性注入,确保代理对象可安全使用属性值[^1^][^4^]。资源高效利用
五、无法解决的场景
构造器循环依赖:实例化阶段无法提前暴露半成品对象[^4^][^5^]。
原型作用域 Bean:每次获取新实例,无法通过缓存解决[^4^][^5^]。
特殊处理器干扰:如 BeanPostProcessor
或 BeanFactoryPostProcessor
参与依赖链,可能中断缓存机制[^4^][^5^]。
总的来说,Spring 的三级缓存机制通过分层存储 Bean 的不同状态(实例化 → 属性注入 → 初始化完成),结合工厂模式动态生成代理对象,巧妙解决了循环依赖问题。这一机制不仅保证了Bean生命周期的正确性,还兼容了 AOP 等高级特性,是 Spring IoC 容器的核心设计之一。
Spring 通过 三级缓存机制 来解决 单例 Bean 的循环依赖 问题。以下是其核心原理和解决过程:
支持解决的循环依赖类型
什么是循环依赖?
当两个或多个 Bean 相互依赖,形成闭环时,就构成了循环依赖。例如:
class A {
private B b;
}
class B {
private A a;
}
在创建 A 时需要注入 B,而创建 B 又需要注入 A,形成循环。
Spring 如何解决?
Spring 使用 三级缓存机制 来处理循环依赖:
1. 一级缓存(singletonObjects) 存放已经完全初始化好的 Bean。
2. 二级缓存(earlySingletonObjects) 存放提前暴露的“早期 Bean”(尚未完全初始化)。
3. 三级缓存(singletonFactories) 存放 Bean 工厂(ObjectFactory),用于创建代理对象(如 AOP 代理)。
解决流程(以 A → B → A 为例)
开始创建 Bean A
填充 A 的属性
开始创建 Bean B
B 获取 A 的依赖
B 完成初始化
继续初始化 A
为什么构造器注入无法解决?
构造器注入在实例化时就需要所有依赖对象,而此时依赖对象可能尚未创建,因此 Spring 无法提前暴露 Bean,导致循环依赖无法解决。
总结
Spring 解决循环依赖的关键在于:
Spring 的这一设计在保证灵活性的同时,有效地解决了常见的循环依赖问题。
Spring 解决循环依赖的核心机制是通过三级缓存(Three-Level Cache)实现的,它允许在对象完全初始化之前提前暴露引用,从而打破环依赖关系。
具体实现原理如下:
三级缓存结构:
解决过程:
适用范围:
代码层面的核心逻辑在DefaultSingletonBeanRegistry
中,关键方法包括:
getSingleton()
:从缓存获取或创建BeanaddSingletonFactory()
:添加对象工厂到三级缓存doCreateBean()
:创建Bean实例并处理依赖这种机制既保证了Bean的完整性,又解决了循环依赖问题,是Spring容器的重要特性之一。
83.46MB · 2025-10-19
289.00M · 2025-10-19
113.53MB · 2025-10-19