使用三级缓存来解决循环依赖问题, 注意:只能解决set方式的依赖注入,构造器方式的不行
一级缓存:singletonObjects,单例对象池,存放完整的SpringBean,也就是走完了整个bean创建生命周期过程。
二级缓存:earlySingletonObjects,早期单例对象。起到复用的作用,多个类都有循环引用该类,那么直接取出来就行。
三级缓存:singletonFactories,单例工厂对象。起到创建代理对象的作用,比如AOP等增强,将实例对象封装增强后返回。
我们使用案例说明一下,假如A类依赖B对象, B依赖A对象。
具体步骤如下:
1.A依赖B,B依赖A,容器将所有beanName循环出来依次加载bean
2.先实例化A,默认允许开启循环依赖,封装A对象单例工厂对象放入三级缓存中
3.设置A属性值(属性注入),发现依赖B对象,先从一级缓存缓存查找,没有的话去二级缓存查找,没有的话最后从三级缓存查找。
4.最终未发现B类对一个的实例,还没有被加载,然后先去加载实例化B对象,并且封装B对象对应单例工厂对象,放入三级缓存。
5.设置B属性值(属性注入),发现依赖A对象,先从一级缓存缓存查找,没有的话去二级缓存查找,没有的话最后从三级缓存查找。
6.找到刚才放入三级缓存中的A对象封装的单例工厂对象,然后调用扩展方法,再创建A类的代理对象放入二级缓存中返回。
7.此时B对象属性装配完毕,B对象正常创建放入一级缓存,删除三级缓存对应单例工厂对象。
8.此时返回刚才创建的B对象给A对象里面对应赋值。
9.此时A属性装配完毕,将生成的A对象的代理对象赋值给A对象后,放入一级缓存中,删除二级缓存中对应对象。
那使用两级缓存不行吗,为什么一定要用到三级缓存呢?
其实代码实现上完全可以的,但是考虑到设计模式上一级缓存中都是跑完全流程后完整的对象,
如果直接将三级缓存中生产的不完整对象放入一级缓存,违背了单一职责原则,而且也不好维护,更失去了扩展的功能。