定义了以下两个bean(单例),看看spring是怎么生产出来提供给我们用的。
@Service
public class TestA {
@Autowired
private TestB testB;
}
@Service
public class TestB {
@Autowired
private TestA testA;
}
这个大家一看就知道怎么回事,我想要讲的是什么。循环依赖么,看上去是怎么也绕不开的话题,平常开发中会在不经意之间就使用上了,我们就从这里出发看看,spring是怎么解决的,但是重点是要了解bean的实例化、初始化流程。
还是比较喜欢图,因为比文字短,且看的清楚。
图虽然清晰但是也要加文字的,不然也不能说的很清楚。
图一中绿色加数字的是执行的方法,并按照数字从小到大顺序执行,箭头对应的方块是重要的参数,注意本文撇去了Aop相关的步骤。
TestA,获取流程:
- getBean,获取bean入口
- doGetBean
- getSingleton,重要方法(解决循环依赖),这个时候会执行到①,会去一级缓存(singletonObjects)获取为null,但是isSingletonCurrentlyInCreation(beanName)的方法为false,没有在创建中,返回是null.
- markBeanAsCreated,标记当前bean在创建中
- getSingleton,注意这个方法跟3不是同一个,参数不一样,重要参数singletonFactory
getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
5.1.1 beforeSingletonCreationation,标记为TestA创建中
5.1.2 singletonFactory.getObject(),或执行传入的代码
-
createBean,开始创建bean
-
resolveBeforeInstantiation,实例化前的操作,先忽略
-
doCreateBean
-
createBeanInstance,实例化一个TestA。《springboot启动bean加载处理器ConfigurationClassPostProcessor 四(@bean注解)》
a: instantiateUsingFactoryMethod 工厂方式创建bean(之前在@bean注解中介绍过) b: instantiateBean
-
addSingletonFactory, 向三级缓存对象singletonFactories,放入一个ObjectFactory<?> singletonFactory,对应的key=TestA
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))
11.populateBean, 这个时候如果不存在循环依赖,用不到三级缓存(三级缓存是存在TestA,但是用不到),会直接继续完成初始化
TestA TestB
--------------------------------------------------------------
populateBean(A)
-------------------------------------------------------------
getBean(B)
...
populateBean(B)
--------------------------------------------------------------
getBean(A)
getSingleton(A)
-------------------------------------------------------------
initializeBean(B)
B完成实例化
-------------------------------------------------------------
initializeBean(A)
赋值TestA的属性TestB,这个时候会重新到(方法:1)开始执行,一直执行到TestB的 populateBean,
需要赋值TestA,又回到(方法:1),执行到(方法:3),这个时候会执行到getSingleton ③,
获取到TestA的singletonFactory返回的bean,放入到二级缓存earlySingletonObjects,
并从三级缓存中移除,返回对象TestA(未初始化)。这个时候 TestB会对A进行赋值,并完成初始化。
- initializeBean,实例化TestA
- invokeAwareMethods
- invokeInitMethods
- addSingleton, 把TestA放入到一级缓存singletonObjects中,并冲二级缓存中移除
看看整个过程中,一、二、三级缓存的动态吧。
总结来说,spring解决循环依赖的处理是,把bean的实例化、初始化分开,所以如果bean是构造注入的,那怎么也玩不转了。
接下来就是,搜索一大把问题,
spring可以不要三级缓存吗?,看上去是可以的吧,只要两个缓存就可以了,把TestA创建好后直接放入到二级缓存,TestB要的时候直接拿。
看看我后续的解释吧。。。《springboot ApplicationContext之finishBeanFactoryInitialization(getBean())下》