Spring如何解决循环依赖
三级缓存指什么?
即DefaultSingletonBeanRegistry中的定义的三个map:
1 | /** Cache of singleton objects: bean name to bean instance. */ |
1. 普通Bean的创建
spring首先会利用反射的方法调用bean的构造函数实例化这个对象,过程如下图:



对象实例化完成,但还没有初始化,将这个对象放到三级缓存:singletonFactores中:

注意以下addSingletonFactory这个方法中传入的参数,第一个是字符串类型也就是bean的名字,第二个是一个lambda表达式,相当于传入了一个匿名内部类。完整的方法签名如下图,ObjectFactory这个接口中只有一个方法getObject。也就是说当调用getObject时会调用getEarlyReference这个方法,参数baen就是实例化好的bean对象。


注意上面的两个方法,当存在循环依赖时,populateBean方法中会检测出来,这个下一节详细介绍。
没有循环依赖时,populateBean这个方法会为对象内属性填充赋值,之后进行初始化。看一下initializeBean方法内部:

可以看到,在我们指定初始化方法前后会调用bean后置处理器的两个方法。

之后利用addSingleton方法将对象从三级缓存放到一级缓存中,对象创建完成。

完整的方法调用栈如下:

可以看到当不存在循环依赖时,bean的流向是三级缓存到一级缓存。
2. 当存在循环依赖时
当存在循环依赖,即类A内有B属性,B类内又有A属性时,首先创建A,在populateBean方法内检测到需要B类,那么就会重复上述创建过程,实例化B之后将B放到三级缓存,populateBean时检查到需要A,会将A从三级缓存中移到二级缓存中,同时把A的引用赋给B,B继续执行后面的方法直到创建完成,B从三级缓存移到一级缓存。此时B已经是一个完整的对象了,再把B的引用赋给A,A完成创建,从二级缓存移动到一级缓存中。可以看到Spring主要利用了对象的“中间态”和一个二级缓存解决了循环依赖问题。


注意到存在beanFactory.getBean的方法,当创建A需要B的时候,就会重复上面创建bean的流程。