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);
	// 2、如果缓存里面能拿到实例
	if (sharedInstance != null && args == null) {
		if (logger.isTraceEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				//省略....
			}
		}
		// 改方法是FactoryBean接口的调用入口
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
	//省略....
}

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;
}

其实这段方法没啥代码逻辑的,就是根据beanName去缓存里面获取实例,如果存在实例就直接返回,不存在就返回一个null 。

很显然circularRefA第一次进来,肯定获取到null ,那么代码继续往下执行。


if (mbd.isSingleton()) {
    // 我们转到定义,看看这个方法里面的一些代码逻辑 , 这个方法的第二个参数是一个匿名ObjectFactory接口实现类 ,这个要理解
	sharedInstance = getSingleton(beanName, () -> {
		try {
		    // 创建bean
			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() 流程可参考这篇文章

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值