|
一、什么是循环依赖?什么是三级缓存?
【什么是循环依赖】我很清楚什么是循环依赖。BeanA类依赖BeanB类注入,BeanB类注入A类时,IOC过程中creaBean实例化A后无法直接找到initbeanA。配置函数以创建B对象的实例化。另外,由于B对象需要注入A对象,如果发现对象池中还没有A对象,就可以戴玩偶。
【三级缓存】三级缓存实际上就是三个Map对象,从存放对象的顺序开始
L3缓存singletonFactories存储ObjectFactory,传递匿名内部类,ObjectFactory.getObject()方法最终通过调用getEarlyBeanReference()进行处理
二级缓存earlySingletonObjects存储bean,存储中间bean实例,当对象需要用AOP片替换时,存储代理bean的实例beanProxy
1级缓存(单个池)singletonObjects存储了整个bean实例
/* * cache of singleton objects : bean name to bean instance。*/
Private final mapstring,object singleton objects=new concurrent hashmap(256);
/* * cache of early singleton objects : bean name to bean instance。* */
Private final mapstring,object earlysingletonobjects=new hashmap(16);
/* * cache of singleton factories : bean name to object factory。*/
Private final mapstring,object factory?singleton factories=new hashmap(16);

二、三级缓存如何解决循环依赖?
[如何解决循环依赖]解决循环依赖关系的核心想法是提前暴露,先创建实例化的A,然后在三级缓存singletonFactories中存储实例化的A的LAM BDA表达式,从而获得A实例。没有循环依赖和AOP时
但是,当A对象需要注入B对象时,发现缓存中还没有B对象,需要创建B对象,并按照上述方法将其添加到三级缓存singletonFactories中,B对象需要注入A对象。这时,从半成品缓存中获取半成品对象A,通过缓存的LAM BDA表达式创建A实例对象,并将其放置在二级缓存Earlysingletonobe中。
B对象现在可以
以注入A对象实例和初始化自己,之后将完成品B对象放入完成品缓存singletonObjects。但是当有aop时,B对象还没有把完成品B对象放入完成品缓存singletonObjects中,B对象初始化后需要进行代理对象的创建,此时需要从singletonFactories获取bean实例对象,进行createProxy创建代理类操作,这是会把proxy&B放入二级缓存earlySingletonObjects中。这时候才会把完整的B对象放入完成品一级缓存也叫单例池singletonObjects中,返回给A对象。
A对象继续注入其他属性和初始化,之后将完成品A对象放入完成品缓存。

三、使用二级缓存能不能解决循环依赖?
一定是不行,我们只保留二级缓存有两个可能性保留一二singletonObjects和earlySingletonObjects,或者一三singletonObjects和singletonFactories
【只保留一二singletonObjects和earlySingletonObjects】
流程可以这样走:实例化A ->将半成品的A放入earlySingletonObjects中 ->填充A的属性时发现取不到B->实例化B->将半成品的B放入earlySingletonObjects中->从earlySingletonObjects中取出A填充B的属性->将成品B放入singletonObjects,并从earlySingletonObjects中删除B->将B填充到A的属性中->将成品A放入singletonObjects并删除earlySingletonObjects。
这样的流程是线程安全的,不过如果A上加个切面(AOP),这种做法就没法满足需求了,因为earlySingletonObjects中存放的都是原始对象,而我们需要注入的其实是A的代理对象。
【只保留一三singletonObjects和singletonFactories】
流程是这样的:实例化A ->创建A的对象工厂并放入singletonFactories中 ->填充A的属性时发现取不到B->实例化B->创建B的对象工厂并放入singletonFactories中->从singletonFactories中获取A的对象工厂并获取A填充到B中->将成品B放入singletonObjects,并从singletonFactories中删除B的对象工厂->将B填充到A的属性中->将成品A放入singletonObjects并删除A的对象工厂。
同样,这样的流程也适用于普通的IOC已经有并发的场景,但如果A上加个切面(AOP)的话,这种情况也无法满足需求。
因为拿到ObjectFactory对象后,调用ObjectFactory.getObject()方法最终会调用getEarlyBeanReference()方法,getEarlyBeanReference这个方法每次从三级缓存中拿到singleFactory对象,执行getObject()方法又会产生新的代理对象
所有这里我们要借助二级缓存来解决这个问题,将执行了singleFactory.getObject()产生的对象放到二级缓存中去,后面去二级缓存中拿,没必要再执行一遍singletonFactory.getObject()方法再产生一个新的代理对象,保证始终只有一个代理对象。
getSingleton()、getEarlyBeanReference() 源码如下
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName); // 先从一级缓存拿
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName); // 拿二级缓存
if (singletonObject == null && allowEarlyReference) {
// 拿三级缓存
ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 最终会调用传入的匿名内部类getEarlyBeanReference()方法,这里面没调用一次会生成一个新的代理对象
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
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;
} |
|