循环依赖一般是指两个类中互相注入彼此,这种情况下如果两个类都要作为bean放到spring容器里,则都要进行bean的生命周期从而在执行属性填充(依赖注入)时就会报错,因为进入了死循环,好在spring使用了三级缓存解决了这个问题,
但如果是构造函数的注入即便是spring也不能解决。
在讲解spring如何解决相互依赖之前先了解这个三级缓存到底是什么,其实说到底这三级缓存就是三个map集合。
图中的singletonObjects就是一级缓存,一个初始化大小为256的ConcurrentHashMap,也是我们每次常说的spring容器(IOC容器,也叫单例池),里面存放的是经过完整bean生命周期的对象(也有可能是代理对象)。
图中的singletonFactories就是三级缓存,一个初始化大小为16的HashMap,它的value是一个lambda表达式,执行表达式里的getObject()方法就会返回一个对象(一个不完整的对象)
图中的earlySingletonObjects就是二级缓存,也是一个初始化大小为16的HashMap,它存放的是通过取出执行三级缓存中lambda表示调用getObject()方法之后得到的对象(就是把原来存在于三级缓存里的东西移入二级缓存)
这里再讲解springBean的生命周期:
实例化、属性填充、初始化、销毁
更具体点:class--->(在多构造函数情况下先推断使用哪个构造函数)实例化得到对象--->属性填充(依赖注入)--->初始化(通过实现接口或加注解执行某些方法给某些属性进行初始化赋值)---->可能需要AOP生成代理对象--->生成bean放入spring容器--->销毁
循环依赖,例如AService和Bservice互相注入,并且都是有特殊注解(@Component、@Service等)都要成为bean
如果先加载AService,先实例化生成对象,再进行属性填充,发现里面需要BService的bean,就去创建BService的bean,又到属性填充时发现需要AService的bean,这时就发生了相互依赖。
解决思路如下:
AService在实例化生成一个不完整对象时,把它放在三级缓存中(实际放入的不是对象而是一个lambda表达式,执行表达式才能得到对象),发现依赖BService的bean,先去一级缓存里面找,发现找不到,就又去二级缓存里面找,
发现又找不到,再去三级缓存里面找还是找不到,就去创建BService的bean从而又开始了BService的bean生命周期,同样先实例化得到对象放到三级缓存,在属性填充时发现依赖AService的bean,就去一级缓存里面找,发现找不到,
又去二级缓存里面找,也找不到就去三级缓存里面找,找到了前面AService放到三级缓存里面的lambda表达式,执行表达式得到对象并放到二级缓存里面同时删除三级缓存里面的AService的lambda,如下图所示。
原文:https://www.cnblogs.com/attachment-1900/p/15106497.html