7、Spring源码-循环依赖
@Component
public class AService {
@Autowired
private Bservice bService;
public void test() {
System.out.println(bService);
}
}
@Component
public class BService {
@Autowired
private Aservice aService;
public void test() {
System.out.println(aService);
}
}那么如何打破这个循环,加个中间人(缓存)
A的Bean在创建过程中,在进行依赖注入之前,先把A的原始Bean放入缓存(提早暴露,只要放到缓存,其他Bean需要时就可以从缓存中拿),放入缓存后,再进行依赖注入,此时A的Bean依赖了B的Bean,如果B的Bean不存在,则需要创建B的Bean,而创建B的Bean的过程和A一样,也是先创建一个B对象,然后把B的对象提早暴露出来放入缓存中,然后在对B的对象进行依赖注入A,此时能从缓存中拿到A的对象,B的对象依赖注入完了之后,B的生命周期结束,那么A的生命周期也能结束。
但是Spring有个AOP的功能,是在初始化后处理的,使用的是AnnotationAwareAspectJAutoProxyCreator是xxxxBeanPostProcessor(Bean后置处理器)的某一个实现类。也是AbstractAutoProxyCreator的实现类,而在Spring中AOP利用的要么是JDK动态代理,要么CGLib的动态代理,所以如果给一个类中的某个方法设置了切面,那么这个类最终就需要生成一个代理对象。代理后就不是A的原始对象。如果只有一个缓存处理,显然无法满足AOP需求,因为最终需要的是代理对象。
一、三级缓存
三级缓存是通用的叫法。
一级缓存为:singletonObjects:缓存的是已经经历了完整生命周期的bean对象。
二级缓存为:earlySingletonObjects:比singletonObjects多了一个early,表示缓存的是早期的bean对象。早期是什么意思?表示Bean的生命周期还没走完就把这个Bean放入了earlySingletonObjects。
三级缓存为:singletonFactories:缓存的是ObjectFactory,表示对象工厂,表示用来创建早期bean对象的工厂。
1.2、另外的缓存
二、分析
2.1、Bean的生成
A类--->生成一个普通对象-->属性注入-->基于切面生成一个代理对象(AOP)-->把代理对象放入singletonObjects单例池中。
完整的生命周期前往:4、Spring源码-bean的生命周期
2.2、处理循环依赖中的AOP问题
AOP可以说是Spring中除开IOC的另外一大功能,而循环依赖又是属于IOC范畴的,所以这两大功能想要并存,Spring需要特殊处理。如何处理的,就是利用了singletonFactories(第三级缓存)。
首先,singletonFactories(三级缓存)中存储的是某个beanName对应的ObjectFactory,在bean的生命周期中,生成完原始对象之后,就会构造一个ObjectFactory存入singletonFactories(三级缓存)中。
这个ObjectFactory是一个函数式接口,支持Lambda表达式:() -> getEarlyBeanReference(beanName, mbd, bean)
上面的Lambda表达式就是一个ObjectFactory,执行该Lambda表达式就会去执行getEarlyBeanReference()方法,而该方法如下:
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;
}该方法会去执行SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference()方法,而这个接口下的实现类中只有两个类实现了这个方法,一个是AbstractAutoProxyCreator,一个是InstantiationAwareBeanPostProcessorAdapter,它的实现如下:
// InstantiationAwareBeanPostProcessorAdapter
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}
// AbstractAutoProxyCreator
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}getEarlyBeanReference()方法首先得到一个cachekey,cachekey就是beanName。
然后把beanName和bean(这是原始对象)存入earlyProxyReferences中调用wrapIfNecessary进行AOP,得到并返回一个代理对象。
什么时候调用getEarlyBeanReference方法呢。回到循环依赖场景中,如图:
A原始对象生成一个ObjectFactory:这个ObjectFactory就是上面说的labmda表达式,中间有getEarlyBeanReference方法(存入singletonFactories时并不会执行lambda表达式,也就是不会执行getEarlyBeanReference方法)
需要A(三级缓存singletonFactories中获取):从singletonFactories(三级缓存)根据beanName得到一个ObjectFactory,然后执行ObjectFactory,也就是执行getEarlyBeanReference方法,此时会得到一个A原始对象经过AOP之后的代理对象,然后把该代理对象放入earlySingletonObjects(二级缓存)中,还要放入earlyProxyReferences缓存中,表示已经经过AOP了。
注意:此时,我们只得到了A原始对象的代理对象,这个对象还不完整,因为A原始对象还没有进行属性填充,所以此时不能直接把A的代理对象放入singletonObjects(一级缓存)中。
当B创建完了之后,A继续进行生命周期,而A在完成属性注入后,会按照它本身的逻辑去进行AOP,而此时我们知道A原始对象已经经历过了AOP,所以对于A本身而言,不会再去进行AOP了,那么怎么判断一个对象是否经历过了AOP呢?会利用上文提到的earlyProxyReferences,在AbstractAutoProxyCreator的postProcessAfterInitialization方法中,会去判断当前beanName是否在earlyProxyReferences,如果在则表示已经提前进行过AOP了,无需再次进行AOP。
对于A对象而言,进行了AOP的判断后,以及BeanPostProcessor(Bean的后置处理器)的执行之后,就需要把A对应的对象放入singletonObjects(一级缓存)中,此时需要从earlySingletonObjects(二级缓存)中得到代理对象,然后入singletonObjects(一级缓存)中。
三、总结
singletonObjects:缓存经过了完整生命周期的bean。
earlySingletonObjects:缓存未经过完整生命周期的bean,如果某个bean出现了循环依赖,就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects(二级缓存)中,这个bean如果要经过AOP,那么就会把代理对象放入earlySingletonObjects(二级缓存)中,否则就是把原始对象放入earlySingletonObjects(二级缓存),但是不管怎么样,就是是代理对象,代理对象所代理的原始对象也是没有经过完整生命周期的,所以放入earlySingletonObjects(二级缓存)我们就可以统一认为是未经过完整生命周期的bean。
singletonFactories:缓存的是一个ObjectFactory,也就是一个Lambda表达式。在每个Bean的生成过程中,经过实例化得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到,如果当前Bean没有出现循环依赖,那么这个Lambda表达式没用,当前bean按照自己的生命周期正常执行,执行完后直接把当前bean放入singletonObjects(一级缓存)中,如果当前bean在依赖注入时发现出现了循环依赖,则从三级缓存中拿到Lambda表达式,并执行Lambda表达式得到一个对象,并把得到的对象放入二级缓存((如果当前Bean需要AOP,那么执行lambda表达式,得到就是对应的代理对象,如果无需AOP,则直接得到一个原始对象))。
earlyProxyReferences:用来记录某个原始对象是否进行过AOP了。
singletonsCurrentlyInCreation:是一个Set<String>,记录正在创建的Bean的BeanName。
版权声明
非特殊说明,本文由Zender原创或收集发布,欢迎转载。
ZENDER




发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。