Spring三级缓存解决循环依赖问题
循环依赖的产生
在多个对象之间产生循环的互相引用的关系,在bean的初始化过程中,就会出现“先有蛋还是先有鸡”的问题。举个例子:
@Component
public class A{
@Autowired
private B b;
}
@Component
public class B{
@Autowired
private A a;
}
此时,在bean的创建过程中,A创建时要在初始化过程中注入B,但B同时也要注入A,
就会产生循环依赖的问题。
三级缓存的名字及其结构
一级缓存(单例池) -> singletonObjects ->ConcurrentHashMap
二级缓存 -> earlySingletonObjects -> ConcurrentHashMap
三级缓存 -> singletonFactories -> HashMap
三级缓存如何解决循环依赖
一级缓存(单例池):用来存储IOC容器最终生成的单例bean;
二级缓存 :保存new出来的不完整对象(因为此时bean的创建过程还未结束),这样当单例池中找不到依赖的属性值时,就可以先从二级缓存中获取到不完整的对象属性,完成对象创建后,在后续的依赖注入过程中,将单例池中对象的引用关系调整完成;
三级缓存(针对AOP):如果引用的对象配置了AOP,那么单例池中最终存储的是代理对象而不是原对象。而生成动态代理是要在对象初始化完成之后才开始进行(此处不了解的可以去看看bean的创建过程)。于是Spring就增加了三级缓存,保存所有对象的动态代理配置信息(lambda表示式)。在发现有循环依赖的时候,将这个动态代理信息获取,提前进行对象的AOP,生成代理对象。
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 先从一级缓存中查找bean是否存在
Object singletonObject = this.singletonObjects.get(beanName);
// 若一级缓存不存在且该对象正在创建中,那就表明产生了循环依赖
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 此时从二级缓存中查找对象是否存在
singletonObject = this.earlySingletonObjects.get(beanName);
// 若对象不存在二级缓存中且允许循环依赖
//(没有AOP就会在这一步之后返回对象值因为创建的时候就会在二级缓存中加入对象属性)
if (singletonObject == null && allowEarlyReference) {
// 双重加锁保证操作原子性
synchronized (this.singletonObjects) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 从三级缓存中查找
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}