栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring源码解析(7)之循环依赖解决

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring源码解析(7)之循环依赖解决

一、前言

        在之前的博客中已经介绍到了Spring的bean的实例化过程,但是介绍到doCreateBean并没有详细去介绍,这里会接着去介绍doCreateBean具体做了什么事情,大家如果没有阅读过之前的博客,可以先去了解一下bean的加载过程,在我之前的博客都有具体的介绍。Spring源码解析(5)之bean实例化过程(上)_jokeMqc的博客-CSDN博客

        下面是Spring解决循环依赖的草图,大家要理解这张图才能够对Spring是如何解决循环依赖以及有哪些循环依赖是Spring无法解决的。

二、什么是循环依赖

        循环依赖就是循环引用,就是两个或多个bean相互之间的持有对方,比如A引用B,B引用A。

     2.1Spring如何解决循环依赖

        Spring容器循环依赖包括构造器循环依赖和setter循环依赖。Spring依赖主要分为一下几种情况。

2.1.1 构造器循环依赖

        表示通过构造器注入构成的循环依赖,次依赖是无法解决的,只能抛出异常。为什么呢?在前面的源码解析中已经看到了,Spring容器将每一个正在创建的单例的放在一个"正在创建的bean"的缓存池里面,如果该bean正在创建过程中,这个缓存一直存在。

        

  
        
    

    
        
    

        针对以上的代码的分析如下:

  1. Spring容器创建"InstanceA"bean,首先去"当前创建的bean的缓存池"查找当前的bean是否正在创建,如果没有发现,则创建该bean,然后把当前的bean放到"当前创建的bean的缓存池"中然后准备其需要的构造参数"InstanceB"。
  2. Spring创建"InstanceB",首先去"当前创建的bean的缓存池"查找当前的bean是否正在创建,如果没有发现,则创建该bean,然后把当前的bean放到"当前创建的bean的缓存池"中然后准备其需要的构造参数"InstanceA"。
  3. 此时Spring容器需要去创建"InstanceA",就会发现该bean正在创建,因为表示循环依赖,就会抛出异常。

2.1.2 sertter循环依赖 

        表示通过setter注入方式构成的循环依赖,对于setter注入造成的循环依赖是通过Spring容器提前暴露刚完成但未初始化的bean来完成的,而且只能够解决单例作用域的bean,因为prototype并不会提前放入到缓存中。

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, new ObjectFactory() {
				@Override
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		} 

         具体步骤如下:

  1. Spring容器创建单例"InstanceA"bean,首先根据午餐构造器创建bean,会判断当前bean, “是否单例&是否允许循环依赖&是否正在创建bean”,如果满足会提前将该早期对象(ObjectFactory)提前暴露到三级缓存中,然后进行属性赋值,setter注入"InstanceB"。
  2. Spring容器创建单例"InstanceB",首先根据无参构造器创建bean,然后会将该bean提前暴露到三级缓存中,然后setter注入"IntanceA".
  3. 进行注入"InstanceA"由于提前暴露了ObjectFactory工厂,从而使用它返回提前暴露一个创建中的bean。
2.1.3 prototype范围的依赖处理

        对于"prototype"作用域bean,Spring容器无法完成依赖注入,因为Spring容器不进行缓存"prototype"作用域的bean,因此无法提前暴露一个创建中的bean。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号