问题:怎么解决循环依赖的
首先配置两个类A,B。A中有B属性,B中有A属性
三级缓存都有啥
singletonObjects :一级缓存,已经创建好的Bean的全局缓存earlySingletionObjects :二级缓存,提前暴露的Bean的全局缓存,但是还在创建中。
- 如果不存在AOP,这个缓存已经足以解决循环依赖的问题
- 但是如果有AOP,就需要三级缓存
singletonFactories :三级缓存,单例工厂的缓存
- 三级缓存存的内容是ObjectFactory,一个函数式接口
- 在A实例化的时候,如果是正在创建的状态,就会放进去() -> getEarlyBeanReference(beanName, mbd, bean)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
源码分析
首先对bean中引用的bean,会标记为RuntimeBeanReference 类型
在实例化的时候,首先根据解析的BeanDefinitions集合,按顺序实例化A和B 在实例化A的过程中在AbstractAutowireCapableBeanFactory#doCreateBean 中有如下方法对循环依赖进行处理
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
然后在AbstractAutowireCapableBeanFactory#populateBean 中有调用方法applyPropertyValues 中,扫描到要注入的属性B还没有注入,
又回到了doGetBean
结论一:如果Bean里还有Bean,就会先去实例化内部的Bean
1、和A一样,B先去一级缓存加载,没有就和A一样在三级缓存中放入() -> getEarlyBeanReference(beanName, mbd, bean)
2、B里也有A,B在populateBean 时,也会加载A
3、这时又到了第二次加载A,第二次加载A发现一级二级缓存都没有,但是三级缓存中有值,就是之前通过lambda表达式设置的ObjectFactory:() -> getEarlyBeanReference(beanName, mbd, bean)
4、这时候通过这个ObjectFactory来获取A的实例,点进去看看
发现又回到开始的addSingletonFactory方法,这时候计算参数中的lambda表达,传入一个beanName,beanDefinition,bean本身的引用
这里面会判断是否需要AOP的一些PostProcessors操作,如果需要就会生成AOP的代理类,如果不需要就直接返回这个bean
5、所以,此时就会返回A的引用,但是A现在内部的B属性任然为空
6、然后将A:A的未完成的引用 放进二级缓存,将A的ObjectFactory从三级缓存中移除
7、返回,现在A中的B获取到了A的引用,此时A还是未完成创建的状态
8、一直返回,到之前resolveValueIfNecessary ,发现B已经解析到了内部属性A,但是A还没完成创建
?
9、然后返回到B的populateBean结束后,可以看到B内的A已经引用上了
10、然后层层返回,回到A的getSingleton ,此时A中的getObject已经拿到了封装好A的B
11、A现在拿到了封装好A的B,但是还没装填,注意:很重要,此处只是拿到了,装填得再出去一层
接下来对B进行addSingleton 操作,放进一级缓存,从二级三级缓存中移除出B
12、再返回,在A内部,把B深拷贝进A
13、此时返回到A的populateBean之后,循环引用问题已经解决了
14、最后在addSingleton中将A从二级三级缓存中移除,放入一级缓存
缓存中内存流程图
|