Spring如何解决循环依赖
1,什么是循环依赖
简单的说就是A依赖B,B依赖C,C依赖A这样就构成了循环依赖。
循环依赖分为构造器依赖和属性依赖,众所周知的是Spring能够解决属性的环依赖(set注入)。下文将从源码角度分析Spring是如何解决属性的循环依赖。
2,思路
如何解决循环依赖,Spring主要的思路就是依据三级缓存,在实例化A时调用doGetBean,发现A依赖的B的实例,此时调用doGetBean去实例B,实例化的B的时候发现又依赖A,如果不解决这个循环依赖的话此时的doGetBean将会无限循环下去,导致内存溢出,程序奔溃。spring引用了一个早期对象,并且把这个”早期引用”并将其注入到容器中,让B先完成实例化,此时A就获取B的引用,完成实例化。
3,三级缓存
Spring能够轻松的解决属性的循环依赖正式用到了三级缓存,在AbstractBeanFactory中有详细的注释。
一级缓存:singletonObjects,存放完全实例化属性赋值完成的Bean,直接可以使用。
二级缓存:earlySingletonObjects,存放早期Bean的引用,尚未属性装配的Bean三级缓存:singletonFactories,
三级缓存,存放实例化完成的Bean工厂。
什么是循环依赖
简单的说就是A依赖B,B依赖C,C依赖A这样就构成了循环依赖。
开撸
先上一张流程图看看Spring是如何解决循环依赖的
上图标记蓝色的部分都是涉及到三级缓存的操作,下面我们一个一个方法解析
【1】 getSingleton(beanName):源码如下:
从源码可以得知,doGetBean最初是查询缓存,一二三级缓存全部查询,如果三级缓存存在则将Bean早期引用存放在二级缓存中并移除三级缓存。(升级为二级缓存)
【2】addSingletonFactory:源码如下
从源码得知,Bean在实例化完成之后会直接将未装配的Bean工厂存放在三级缓存中,并且移除二级缓存
【3】addSingleton:源码如下: