Spring中怎么解决循环依赖


今天就跟大家聊聊有关Spring中怎么解决循环依赖,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
循环依赖,其实就是循环引用,就是两个或者两个以上的 bean 互相引用对方,最终形成一个闭环,如 A 依赖 B,B 依赖 C,C 依赖 A。如下图所示:Spring中的循环依赖,其实就是一个死循环的过程,在初始化 A 的时候发现依赖了 B,这时就会去初始化 B,然后又发现 B 依赖 C,跑去初始化 C,初始化 C 的时候发现依赖了 A,则又会去初始化 A,依次循环永不退出,除非有终结条件。 香港云主机一般来说,Spring 循环依赖的情况有两种:构造器的循环依赖。 field 属性的循环依赖。 对于构造器的循环依赖,Spring 是无法解决的,只能抛出 BeanCurrentlyInCreationException 异常表示循环依赖,所以下面我们分析的都是基于 field 属性的循环依赖。在前文 Spring Ioc源码分析 之 Bean的加载(三):各个 scope 的 Bean 创建 中提到,Spring 只解决 scope 为 singleton 的循环依赖。对于scope 为 prototype 的 bean ,Spring 无法解决,直接抛出 BeanCurrentlyInCreationException 异常。为什么 Spring 不处理 prototype bean 呢?其实如果理解 Spring 是如何解决 singleton bean 的循环依赖就明白了。这里先留个疑问,我们先来看下 Spring 是如何解决 singleton bean 的循环依赖的。在AbstractBeanFactory 的 doGetBean()方法中,我们根据BeanName去获取Singleton Bean的时候,会先从缓存获取。
代码如下:这段代码涉及的3个关键的变量,分别是3个级别的缓存,定义如下:getSingleton()的逻辑比较清晰:首先,尝试从一级缓存singletonObjects中获取单例Bean。如果获取不到,则从二级缓存earlySingletonObjects中获取单例Bean。如果仍然获取不到,则从三级缓存singletonFactories中获取单例BeanFactory。最后,如果从三级缓存中拿到了BeanFactory,则通过getObject()把Bean存入二级缓存中,并把该Bean的三级缓存删掉。看到这里可能会有些疑问,这3个缓存怎么就解决了singleton循环依赖了呢?
先别着急,我们现在分析了获取缓存的代码,再来看下存储缓存的代码。 在 AbstractAutowireCapableBeanFactorydoCreateBean() 方法中,有这么一段代码:这段代码就是put三级缓存singletonFactories的地方,其核心逻辑是,当满足以下3个条件时,把bean加入三级缓存中:单例允许循环依赖当前单例Bean正在创建addSingletonFactory(String beanName, ObjectFactory> singletonFactory) 方法,代码如下:从这段代码我们可以看出,singletonFactories 这个三级缓存才是解决 Spring Bean 循环依赖的关键。同时这段代码发生在 createBeanInstance(...) 方法之后,也就是说这个 bean 其实已经被创建出来了,但是它还没有完善(没有进行属性填充和初始化),但是对于其他依赖它的对象而言已经足够了(已经有内存地址了,可以根据对象引用定位到堆中对象),能够被认出来了。到这里我们发现三级缓存 singletonFactories 和 二级缓存 earlySingletonObjects 中的值都有出处了,那一级缓存在哪里设置的呢?在类 DefaultSingletonBeanRegistry 中,可以发现这个 addSingleton(String beanName, Object singletonObject) 方法,代码如下:该方法是在 #doGetBean(…) 方法中,处理不同 scope 时,如果是 singleton调用的,如下图所示: 也就是说,一级缓存里面是完整的Bean。小结:一级缓存里面是完整的Bean,是当一个Bean完全创建后才put三级缓存是不完整的BeanFactory,是当一个Bean在new之后就put(没有属性填充、初始化)二级缓存是对三级缓存的易用性处理,只不过是通过getObject()方法从三级缓存的BeanFactory中取出Bean现在我们再来回顾下Spring解决单例循环依赖的方案:Spring 在创建 bean 的时候并不是等它完全完成,而是在创建过程中将创建中的 bean 的 ObjectFactory 提前曝光(即加入到 singletonFactories 三级缓存中)。这样,一旦下一个 bean 创建的时候需要依赖 bean ,则从三级缓存中获取。举个栗子
比如我们团队里要报名参加活动,你不用上来就把你的生日、性别、家庭信息什么的全部填完,你只要先报个名字,统计下人数就行,之后再慢慢完善你的个人信息。核心思想:提前暴露,先用着最后来描述下就上面那个循环依赖 Spring 解决的过程:首先 A 完成初始化第一步并将自己提前曝光出来(通过 三级缓存 将自己提前曝光),在初始化的时候,发现自己依赖对象 B,此时就会去尝试 get(B),这个时候发现 B 还没有被创建出来然后 B 就走创建流程,在 B 初始化的时候,同样发现自己依赖 C,C 也没有被创建出来这个时候 C 又开始初始化进程,但是在初始化的过程中发现自己依赖 A,于是尝试 get(A),这个时候由于 A 已经添加至缓存中(三级缓存 singletonFactories ),通过 ObjectFactory 提前曝光,所以可以通过 ObjectFactory#getObject() 方法来拿到 A 对象,C 拿到 A 对象后顺利完成初始化,然后将自己添加到一级缓存中回到 B ,B 也可以拿到 C 对象,完成初始化,A 可以顺利拿到 B 完成初始化。到这里整个链路就已经完成了初始化过程了http://cmsblogs.com/?p=todo (小明哥)看完上述内容,你们对Spring中怎么解决循环依赖有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注开发云行业资讯频道,感谢大家的支持。

相关推荐: 怎么使用CSS3按钮鼠标悬浮实现光圈效果

这篇文章主要讲解了“怎么使用CSS3按钮鼠标悬浮实现光圈效果”,文中的讲解内容简 香港云主机单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么使用CSS3按钮鼠标悬浮实现光圈效果”吧!1 、HTML相关知识点  HTML(超文本标…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 07/26 11:51
下一篇 07/26 12:45

相关推荐