Spring循环依赖注入流程分析

Spring循环依赖注入流程分析

我们在使用Spring做开发的时候经常会遇到以下这种情况,CircularRefA 对象里面需要注入CircularRefB,CircularRefB对象里面需要依赖注入CircularRefA 。代码如下:


@Component
public class CircularRefA {
    @Autowired
    private CircularRefB circularRefB;
}

@Component
public class CircularRefB {

    @Autowired
    private CircularRefA circularRefA;

}

我们开始吧,假设Spring容器先触发beanFactory.get("circularRefA ") 这个动作

circularRefA 第一次doGetBean

//获取一个bean实例
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	final String beanName = transformedBeanName(name);
	Object bean;

	// 1、这个方法很重要要去看看,作用就是从缓冲中拿bean实例
	Object sharedInstance = getSingleton(beanName);
	// 如果缓存里面能拿到实例
	if (sharedInstance != null && args == null) {
		if (logger.isTraceEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		// 改方法是FactoryBean接口的调用入口
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
	else{
	    // 第一次进来会执行else的代码逻辑的
	}
	
	/*******************省略*******************/
	/*******************省略*******************/
	/*******************省略*******************/
	/*******************省略*******************/

}

getSingleton

这个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) {
					// 三级缓存调用getObject()
					singletonObject = singletonFactory.getObject();
					// 三级缓存升级到二级缓存
					this.earlySingletonObjects.put(beanName, singletonObject);
					// 移除三级缓冲
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

其实这段方法没啥代码逻辑的,就是根据beanName去缓存里面获取实例,如果存在实例就直接返回,不存在就返回一个null 。很显然circularRefA第一次进来,肯定获取到null 。
在这里插入图片描述
因为本篇文章主要讲解循环依赖注入,所以其它的一些细节代码我就不贴出来。那我们看else 里面的代码。

if (mbd.isSingleton()) {
    // 我们转到定义,看看这个方法里面的一些代码逻辑 , 这个方法的第二个参数是一个匿名ObjectFactory接口实现类 ,这个要理解
	sharedInstance = getSingleton(beanName, () -> {
		try {
			return createBean(beanName, mbd, args);
		}
		catch (BeansException ex) {
			destroySingleton(beanName);
			throw ex;
		}
	});
	// 这方法是FactoryBean接口的调用入口
	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

// 获取circularRefA 实例
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
	synchronized (this.singletonObjects) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null) {
			if (this.singletonsCurrentlyInDestruction) {
				throw new BeanCreationNotAllowedException(beanName,"代码太多了我把这些删了");
			}
			if (logger.isDebugEnabled()) {
				logger.debug("代码太多了我把这些删了" + beanName + "'");
			}
			// 1、把beanName 加入到singletonsCurrentlyInCreation Set集合中,标志beanName正在创建
			beforeSingletonCreation(beanName);
			boolean newSingleton = false;
			boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
			if (recordSuppressedExceptions) {
				this.suppressedExceptions = new LinkedHashSet<>();
			}
			try {
			    //2、这个就是调用刚才介绍的-匿名ObjectFactory接口实现类方法,
			    // 换句话说就是调用到createBean() 方法
				singletonObject = singletonFactory.getObject();
				newSingleton = true;
			}
			catch (IllegalStateException ex) {
				singletonObject = this.singletonObjects.get(beanName);
				if (singletonObject == null) {
					throw ex;
				}
			}
			catch (BeanCreationException ex) {
				if (recordSuppressedExceptions) {
					for (Exception suppressedException : this.suppressedExceptions) {
						ex.addRelatedCause(suppressedException);
					}
				}
				throw ex;
			}
			finally {
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = null;
				}
				// 3、当前beanName实例创建完成后,把beanName从singletonsCurrentlyInCreation Set集合中移除
				afterSingletonCreation(beanName);
			}
		    // 4、如果这个是新创建的对象,就要把这个对象放入到singletonObjects 缓存中,
		    // 移除 earlySingletonObjects、singletonFactories缓存中对应的实例
			if (newSingleton) {
				addSingleton(beanName, singletonObject);
			}
		}
		return singletonObject; 
	}
}

上面的getSingleton() 这个方法看了下,也没啥负载的逻辑。

第一步:beforeSingletonCreation() 把“circularRefA” 放入到 singletonsCurrentlyInCreation Set集合中,标志"circularRefA" 正在创建。

第二步:就调用singletonFactory.getObject() 得到"circularRefA" 实例,也就是调用createBean() 方法。

doCreateBean

我们就直接去看createBean() -> doCreateBean() ,doCreateBean() 方法我也只贴依赖注入的核心代码。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
	
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
	    // 1、创建bean实例
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	
	synchronized (mbd.postProcessingLock) {
		if (!mbd.postProcessed) {
			try {
			    //2、来收集bean需要注入的(方法、属性)并且封装成Metadata对象存入缓存中
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			}
			catch (Throwable ex) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Post-processing of merged bean definition failed", ex);
			}
			mbd.postProcessed = true;
		}
	}
	// 是否	单例bean提前暴露
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		if (logger.isTraceEnabled()) {
			logger.trace("Eagerly caching bean '" + beanName +
					"' to allow for resolving potential circular references");
		}
		// 3、这个就是添加三级缓存的地方 ( () -> getEarlyBeanReference(beanName, mbd, bean) ) lamda表达式 , getEarlyBeanReference() 得到一个 ObjectFactory<?>对象
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}
	
	Object exposedObject = bean;
	try {
	    // 4、populateBean方法做依赖注入
		populateBean(beanName, mbd, instanceWrapper);
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	
	/**************************省略**************************/
	/**************************省略**************************/
	
	return exposedObject;
	
}

//添加三级缓存
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
	synchronized (this.singletonObjects) {
		if (!this.singletonObjects.containsKey(beanName)) {
			// 将singletonFactory添加到三级缓存
			this.singletonFactories.put(beanName, singletonFactory);
			// 移除二级缓冲
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}
}

“circularRefA” 第一次进入doCreateBean 主要做了如下事情:

  1. 调用createBeanInstance方法创建了一个CircularRefA 对象实例,这个时候circularRefA 实例是一个半成品,它的属性还没做依赖注入

  2. 来收集bean需要注入的(方法、属性)并且封装成Metadata对象存入缓存中

  3. addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean) ) ,第二个参数就是一个 ObjectFactory 接口的匿名实现类 ,将其放入三级缓存 singletonFactories 中

  4. populateBean() 做依赖注入,因为"circularRefA" 对象了需要注入一个 CircularRefB 实例对象 。在这里依赖注入CircularRefB 实例对象会触发 beanFactory.getBean(“circularRefB”) 操作,然后将其结果反射复制到circularRefA对象中。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
既然触发到beanFactory.getBean(“circularRefB”)操作,是不是又回到getBean方法的起始点 ?

circularRefB 第一次doGetBean

很显然circularRefB第一次进来,走的流程跟circularRefA是一模一样的 。这个要想得通,这个想不通下面就不要看了 。
接下来到了CircularRefB实例做依赖注入circularRefA对象的时候,同样也会触发beanFactory.getBean(“circularRefA”) 的操作 。
在这里插入图片描述

circularRefA 第二次doGetBean

circularRefA 第二次进入了doGetBean() ,同样执行下面的这段代码。代码如下:

Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
	if (logger.isTraceEnabled()) {
		if (isSingletonCurrentlyInCreation(beanName)) {
			logger.trace("代码太多直接删除了");
		}
		else {
			logger.trace("代码太多直接删除了");
		}
	}
	// 这方法是FactoryBean接口的调用入口
	bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

第二次进入getSingleton() 去获取circularRefA 跟第一次进入getSingleton() 获取circularRefA 不同的地方是:“第二次进入getSingleton() 方法的时候,singletonFactories有相应的缓存对象信息了 ” 。这个三级缓存设置上面介绍了 ,内容如下:

在这里插入图片描述
在这里插入图片描述
我还是把getSingleton() 方法在贴出来,看起来方便一点,代码如下:

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) {
					// 三级缓存调用getObject()
					singletonObject = singletonFactory.getObject();
					// 三级缓存升级到二级缓存
					this.earlySingletonObjects.put(beanName, singletonObject);
					// 移除三级缓冲
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

既然在三级缓存里面能获取到 ObjectFactory接口实现类对象,singletonFactory.getObject() 获取"circularRefA" 实例就是调用到
在这里插入图片描述
其实getEarlyBeanReference() 这个方法啥事情也没做,就把前面介绍的 半成品 circularRefA 返回回去
在这里插入图片描述
在这里插入图片描述

总结

  1. 既然成功的拿到【circularRefA】实例,大家在回头想想是不是circularRefB实例要做依赖注入,才引发了beanFactory.getBean(“circularRefA”) 操作。现在 circularRefA 实例已经创建好了( 这个时候circularRefA 还是一个半成品的,circularRefA对象中 circularRefB字段里面还是为NULL ),那么circularRefB 依赖注入是不是可以顺利完成 。 circularRefB依赖注入完成,换句话说circularRefB对应的bean也就创建成功了。

  2. 大家在回头想想是不是circularRefA实例要依赖注入circularRefB,才引发了beanFactory.getBean(“circularRefB”) 操作 。现在circularRefB 实例创建完成了,circularRefA 依赖注入操作是不是也顺利完成了 。此时的circularRefA 实例不再是半成品的。

  3. circularRefA 实例既然不是半成品 ,circularRefB对象中的 【circularRefA】 属性引用的 CircularRefA对象也是一个完整的实例( 它们引用的是同一块内存地址

  4. 要了解createBean() 流程可参考这篇文章

发布了16 篇原创文章 · 获赞 10 · 访问量 7948

猜你喜欢

转载自blog.csdn.net/mnicsm/article/details/103701209