CS-Base
CS-Base copied to clipboard
Spring通过三级缓存解决单例模式循环依赖的步骤好像是错的
Spring通过三级缓存解决单例模式循环依赖的步骤好像是错的,好像应该是:
在 Spring 容器中,三级缓存机制用于解决单例模式下 bean 的循环依赖问题。以下是三级缓存解决循环依赖的详细流程:
1. 创建 bean 实例
当 Spring 容器开始创建一个 bean 时,首先会通过反射创建一个原始的 bean 实例。
2. 将 bean 实例放入三级缓存
在创建完原始 bean 实例后,Spring 容器会立即将这个实例包装成一个 ObjectFactory
,并将其放入三级缓存(singletonFactories
)中。ObjectFactory
是一个工厂对象,它能够提供 bean 的早期引用。
singletonFactories.put(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
3. 填充属性
Spring 尝试为这个原始的 bean 实例填充属性,如果此时发现依赖的属性还未创建,则会尝试创建依赖的 bean。
4. 检查依赖的 bean 是否已经创建
在创建依赖的 bean 时,Spring 容器会重复上述步骤。如果在创建依赖 bean 的过程中又需要依赖原始的 bean,则会触发以下流程:
5. 检查一级缓存
Spring 首先检查一级缓存(singletonObjects
)中是否已经存在所需的 bean 实例。如果存在,直接返回。
6. 检查二级缓存
如果一级缓存中没有找到,Spring 接着检查二级缓存(earlySingletonObjects
)中是否有早期引用。如果存在,直接返回。
7. 检查三级缓存
如果二级缓存中也没有找到,Spring 会检查三级缓存(singletonFactories
)是否有对应的 ObjectFactory
。如果有,Spring 会通过 ObjectFactory
获取早期引用,并将其放入二级缓存,同时从三级缓存中移除。
ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
if (singletonFactory != null) {
Object earlySingletonReference = singletonFactory.getObject();
// 将早期引用放入二级缓存
earlySingletonObjects.put(beanName, earlySingletonReference);
// 从三级缓存中移除
singletonFactories.remove(beanName);
return earlySingletonReference;
}
8. 完成属性填充和初始化
此时,原始 bean 和其依赖的 bean 都有了早期引用,可以继续进行属性填充和初始化。
9. 将完全初始化的 bean 放入一级缓存
当 bean 完成所有初始化步骤后,Spring 会将其从二级缓存中移除,并将其放入一级缓存,供后续使用。
addSingleton(beanName, singletonObject);
总结
通过上述流程,Spring 容器能够解决单例模式下 bean 的循环依赖问题。需要注意的是,这个机制依赖于以下条件:
- bean 必须是单例模式。
- bean 的创建过程不涉及 AOP,或者 AOP 的代理是通过三级缓存中的
ObjectFactory
生成的。 如果这些条件不满足,Spring 可能无法解决循环依赖问题。