spring中Ioc进行bean加载时如何解决循环依赖问题

引言:

循环依赖就是循环引用,就是两个或者多个bean相互之间持有对方,比如A引用B,B引用C,C引用A,它们最终引用成为一个环。循环引用不是循环调用,循环调用是方法之间的调用,循环调用是无法解决的,除非有终结条件,否则就是死循环,最终导致内存溢出或者内存溢出异常。

Spring如何解决循环依赖

Spring中的依赖包括构造器循环依赖, 和setter循环依赖,构造器循环依赖在Spring中无法解决,因为bean实例化的时候最先开始就是通过构造来进行实例化,如果是构造器循环依赖,会造成死循环。这里所解决的循环依赖是setter循环依赖。

解决setter循环依赖:(只适用于单例bean)

对于setter循环依赖是通过Spring容器提前暴露刚完成构造器注入但是未完成其他步骤(比如setter注入,属性注入等,相当于是刚完成实例化的第一步)的bean来完成的,从而使其他bean能够引用到该bean。

具体步骤如下:

  1. Spring容器创“testA”bean, 首先分局无参构造器创建bean,并暴露一个“objectFactory”,用于返回一个提前暴露创建中的bean,并将“testA”标识符放到“当前创建bean池中”,然后进行setter注入“testB”。
  2. Spring容器创“testB”bean, 首先分局无参构造器创建bean,并暴露一个“objectFactory”,用于返回一个提前暴露创建中的bean,并将“testB”标识符放到“当前创建bean池中”,然后进行setter注入“testA”。当进行注入“testA”时,由于提前暴露了“ObjectFactory”工厂,从而使它返回提前暴露一个创建中的bean,而不用再去实例化testA。

具体流程如下图:


接着看spring源码中如何做的:

bean解析完成之后就需要加载也就是实例化bean了,入口方法即为getBean()方法


接着进入doGetBean()方法内:


进入getsingleton(beanName)方法中。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}

这段代码时循环依赖的检测。这个方法首先尝试从singletonObjects中获实例,如果获取不到再从earlySingletonObjects里面获取,如果还是获取不到,在尝试从singletonFactories里面获取beanName对应的ObjectFactory,然后调用ObjectFactory的getObject()方法来创建bean,并放到earlySingletonObjects里面去,并且从singletonFactories里面remove掉这个ObjectFactory。

下面解释以上的出现的map。

  • singletonObjects:用于保存BeanName和创建bean实例之间的关系,bean name -->bean instance
  • singletonFactories:用于保存beanName和创建bean工厂之间的关系,bean name -->ObjectFactory
  • earlySingletonObjects:也是保存BeanName和创建bean实例之间的关系,与singletonObjects的不同之处在于,当一个单例bean被放到这里后,那么当bean还在创建过程中,就可以通过getBean()方法获取了,其目的是用来检测循环引用。

以上是检测循环引用,如果第一次进来没有创建bean,那就只能从头开始创建bean了。

直接跟代码到:(我都跟晕了。。。。)AbstractAutowireCapableBeanFactory 类下的doCreateBean()方法,如下图:addSingletonFactory()方法在属性注入之前也就是 populateBean(beanName, mbd, instanceWrapper) 之前,此时将该bean记录到singletonFactory,接下来如果进行属性注入时候,进行实例化其他类时,解决循环依赖问题。


到这大致了解了spring 如何解决循环依赖,只是大致,里面还有很多判断细节。

发布了102 篇原创文章 · 获赞 49 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/SoWhatWorld/article/details/104560489