请按缩进格式看,应该好理解些。
如果这一篇看不懂,我还写了另一种形式的,纯文字描述。。不知道能不能帮到大家。https://blog.csdn.net/qq_36951116/article/details/100032254
设spring有两个bean,A依赖于B,B也依赖于A,两个都是singleton的。
流程如下:
1、getBean方法获取A,容器中没有->
2、createBean创建A,把该A实例先通过ObjectFactory暴露出去,下次再获取A时,如果A还没有完全创建完,则会通过ObjectFactory先获取提前暴露的A->
3、populateBean填充A的属性,需要注入B->
递归1开始:
3.1、getBean获取B,容器中没有->
3.2、createBean创建B....与2一样...->
3.3、populateBean填充B的属性,需要注入A->
3.4、递归2开始:
3.4.1、getBean获取A,此时A没创建完成,但在第2步中,A的实例已经通过ObjectFactory提前暴露,所以获取到提前暴露的A。
3.4.2、返回提前暴露的A,A此时还没有创建完成(递归调用中),在doGetBean的开始的getSingleton方法中获取到的提前暴露的A。
递归2结束;
3.5、3.3填充B的属性成功,成功注入A(提前暴露的A的引用,中途引用可能被修改)。
3.6、initializeBean调用后置处理器(可能会返回新的代理对象B+,此时无影响)、
3.7、返回已经创建完成的B。
递归1结束;
4、initializeBean调用后置处理器(可能会返回新的代理对象A+,如果返回的是A+而不是A,则对于循环依赖会有影响)、
5、
5.1如果步骤4返回的是A+,(后置处理器返回的可能是A的新实例,也可能是A的代理对象,总之不是提前暴露的A了)
5.1.1、在doCreateBean方法后半段,此时A还在创建过程中,A已经被注入到B中(请看步骤3),并且B是已经创建完成(步骤3的递归1就是创建B的流程),如果条件都符合,则spring直接报异常。
5.2如果步骤4返回的还是A,引用不变的话,那就跳过。直接到步骤6。
6、A创建完成,返回创建A。
为什么要第5步?
这么做就是为了保证A+和A不会同时出现在应用中,为了保证A的实例在spring管理下是单例的。
因为在A这个bean创建完成之前,A的引用已经提前暴露出去,并且被B注入进去了(步骤3.3~3.7),且B已经被标记为最终创建(添加到created集合)。然后A才开始执行第4个步骤。就是因为第4个步骤A可能会被替换为A+,如果没有第5步的判断,就会导致A+的引用被添加到spring容器中,而A的引用则会被B把持着,这种情况,A+和A会同时存在,这就不符合作用域为singleton的设定