什么循环依赖

通俗来讲,就是A依赖B或者B依赖A,或者C依赖自己本身,或是三个以上,例如A依赖B,B依赖C,C又依赖A。如下图

在这里插入图片描述

Spring实例Bean的本质

Spring实例一个bean时候,是首先递归实例化其所依赖的所有bean,直到某个bean没有依赖其他bean,此时就会将该实例返回然后递归的将获取到的bean设置各个上层bean的属性的。

解决方式

Spring通过三级缓存来解决上述问题的:

第一级缓存singletonObjects 在 Spring 容器初始化时,它会创建对象实例并将其放入 singletonObjects 缓存中。这个缓存保存着已经完全初始化对象实例,可以被其他对象直接引用使用

二级缓存:earlySingletonObjects 如果某个对象正在创建过程中,但还未完成初始化,就会将其放入 earlySingletonObjects 缓存中。这个缓存保存着尚未完成初始化的对象实例,只能在对象创建过程中被其他对象引用使用

第三级缓存singletonFactories 当对象正在创建过程中,且存在循环依赖时,会将正在创建的对象实例放入 singletonFactories 缓存中。这个缓存保存着正在创建的对象实例的工厂对象,它是为了解决循环依赖而设计的。

三级缓存解决循环依赖流程

获取A时首先会尝试从一级缓存singletonObjects 中获取;
获取不到就再从二级缓存earlySingletonObjects中获取;
若是还没有尝试从三级缓存singletonFactories获取;
还是没有获取到则再尝试创建A对象
执行doGetBean->createBean->createBeanInstance使用构造器实例化
尝试给A进行初始化时,由于B不存在无法完成初始化,则将半成品A放入第二级缓存中,进入B的创建流程
与先前过程相似,在第三级缓存中放入beanName和表达式sharedInstance进入B的初始化过程
由于在第二级缓存可以找到A,则B可以完成初始化,将成品Bean放入一级缓存中备用,删除三级缓存中的B
同时完成A的初始化,并删除二级缓存中的半成品A

总结

Spring通过三级缓存解决了循环依赖,其中一级缓存为单例池(singletonObjects),二级缓存为早期曝光对象earlySingletonObjects,三级缓存为早期曝光对象工厂(singletonFactories)。
当A、B两个类发生循环引用时,在A完成实例化后,就使用实例化后的对象去创建一个对象工厂添加到三级缓存中,如果A被AOP代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象。
当A进行属性注入时,会去创建B,同时B又依赖了A,所以创建B的同时又会去调用getBean(a)来获取需要的依赖,此时的getBean(a)会从缓存中获取。

先获取到三级缓存中的工厂
调用对象工工厂getObject方法来获取到对应的对象,得到这个对象后将其注入到B中。紧接着B会走完它的生命周期流程,包括初始化、后置处理器等。
当B创建完后,会将B再注入到A中,此时A再完成它的整个生命周期。至此,循环依赖结束

参考链接http://t.csdnimg.cn/E8qu7

原文地址:https://blog.csdn.net/qq_56936805/article/details/134654106

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_22274.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注