06_spring源码循环依赖的解决方式

本文详细解释了Spring容器中循环依赖的概念,以及如何通过设置Bean为单例、依赖注入方式以及利用XML配置来解决循环调用。特别关注了Spring源码中三级缓存机制在处理循环依赖中的作用。
摘要由CSDN通过智能技术生成

什么是循环依赖:简单来说就是在spring容器中A类引用B类,B类引用A类,从而引起循环调用。
图示:
在这里插入图片描述
代码演示

public class A {

	private B b;

	public B getB() {
		return b;
	}

	public void setB(B b) {
		this.b = b;
	}
}

public class B {
	private A a;

	public B() {
	}

	public B(A a) {
		this.a = a;
	}

	public A getC() {
		return a;
	}
}
什么情况下spring能够解决循环依赖
①出现循环依赖的Bean必须要是单例
②依赖注入的方式需要是set方式注入 (但是也有特殊情况,假设你仅仅获取A实例,那么B类中可以是构造注入。原因在于b实例化是在填充属性时进行解决的,如果没有set进行属性赋值 则不会进行B的实例化。但B类实例化时已经存在A的实例,可以直接引用。但在直接获取B实例时报错)当然如果两个都使用set注入更好

直接获取b实例 报错原因是 A类没办法进行set注入,那么不会再填充属性是进行实例化。
如果B类中也是set注入则下面代码不会报错

XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("spring.xml"));
xmlBeanFactory.getBean("b");

源码查看循环依赖解决过程
首先xml配置

	<bean name="a" class="com.gl.pojo.A">
		<property name="b" ref="b"></property>
	</bean>
	<bean name="b" class="com.gl.pojo.B">
		<constructor-arg ref="a" name="a"/>
	</bean>

test演示

	XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("spring.xml"));
	A a = (A)xmlBeanFactory.getBean("a");
	System.out.println(a);
	System.out.println(a.getB());

源码:

三级缓存
//一级缓存 存储初始化后的完整实例
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//二级缓存 存储实例
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
//三级缓存 存储bean工厂
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

核心方法

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				synchronized (this.singletonObjects) {
					// Consistent creation of early reference within full singleton lock
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						singletonObject = this.earlySingletonObjects.get(beanName);
						if (singletonObject == null) {
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
								singletonObject = singletonFactory.getObject();
								//放到二级缓存
								this.earlySingletonObjects.put(beanName, singletonObject);
								//从三级缓存移除
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}

一开始三个缓存都是空的
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
这个addSingletonFactory() 方法第一次将 beanFactoy存到三级缓存。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// 实例化bean
		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			// 有可能在本Bean创建之前,就有其他Bean把当前Bean给创建出来了(比如依赖注入过程中)
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			// 创建Bean实例
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// 后置处理合并后的BeanDefinition
		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// 为了解决循环依赖提前缓存单例创建工厂
		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		//主动缓存单例,以便能够解析循环引用,即使是由BeanFactoryAware等生命周期接口触发时也是如此。
		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");
			}
			// 循环依赖-添加到三级缓存  后续循环依赖 调用getEarlyBeanReference 方法获取实例
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		//初始化bean实例。
		Object exposedObject = bean;
		try {
			// 属性填充
			populateBean(beanName, mbd, instanceWrapper);

			// 初始化
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		if (earlySingletonExposure) {

			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					//获取的到的实例
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					// beanName被哪些bean依赖了,现在发现beanName所对应的bean对象发生了改变,那么则会报错
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			//注册其DisposableBean接口和/或给定的destroy方法,以便在工厂关闭时调用(如果适用)。只适用于单例。
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

之后进行属性填充 发现B实例不存在将创建B实例 核心方法 resolveReference(argName, ref)

public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
		// We must check each value to see whether it requires a runtime reference
		//我们必须检查每个值,看它是否需要运行时引用
		// to another bean to be resolved.
		//到另一个待解析的bean。
		if (value instanceof RuntimeBeanReference) {
			RuntimeBeanReference ref = (RuntimeBeanReference) value;
			//所依赖的bean是一个运行时引用 需要进行解析引用
			return resolveReference(argName, ref);
		}
}

获取 b实例 bean = this.beanFactory.getBean(resolvedName); 类似于xmlBeanFactory.getBean(“a”); 只不过现在resolvedName 是b ,开始执行b的doCreateBean 。重复了上面的过程。再b实例化后填充a属性,此时获取a实例将会执行getSingleton方法,此时三级缓存存在a的beanFactory。
singletonObject = singletonFactory.getObject();
//放到二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
//从三级缓存移除
this.singletonFactories.remove(beanName);

private Object resolveReference(Object argName, RuntimeBeanReference ref) {
		try {
			Object bean;
			Class<?> beanType = ref.getBeanType();
			if (ref.isToParent()) {
				BeanFactory parent = this.beanFactory.getParentBeanFactory();
				if (parent == null) {
					throw new BeanCreationException(
							this.beanDefinition.getResourceDescription(), this.beanName,
							"Cannot resolve reference to bean " + ref +
									" in parent factory: no parent factory available");
				}
				if (beanType != null) {
					bean = parent.getBean(beanType);
				}
				else {
					bean = parent.getBean(String.valueOf(doEvaluate(ref.getBeanName())));
				}
			}
			else {
				String resolvedName;
				if (beanType != null) {
					NamedBeanHolder<?> namedBean = this.beanFactory.resolveNamedBean(beanType);
					bean = namedBean.getBeanInstance();
					resolvedName = namedBean.getBeanName();
				}
				else {
					resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
					//从bean工厂获取bean
					bean = this.beanFactory.getBean(resolvedName);
				}
				this.beanFactory.registerDependentBean(resolvedName, this.beanName);
			}
			if (bean instanceof NullBean) {
				bean = null;
			}
			return bean;
		}
		catch (BeansException ex) {
			throw new BeanCreationException(
					this.beanDefinition.getResourceDescription(), this.beanName,
					"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
		}
	}

b实例的属性填充完成之后执行初始化后存入到一级缓存。 以下是简化代码。之后a继续填充b属性完成a的初始化。


	//创建bean实例 调用 singletonFactory 的 实现 createBean(beanName, mbd, args);
	singletonObject = singletonFactory.getObject();
	newSingleton = true;

	//初始化后执行
	// 将初始化后的bean放到一级缓存 添加到单例池  singletonObjects 和  按注册顺序 的bean名称 registeredSingletons
	if (newSingleton) {
	  addSingleton(beanName, singletonObject);
	}
	return singletonObject;

	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			//将初始化的bean放到一级缓存
			this.singletonObjects.put(beanName, singletonObject);
			//从三级缓存清除
			this.singletonFactories.remove(beanName);
			//从二级缓存清除
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}

大致流程
在这里插入图片描述

	上述我们看到了三级缓存在整个循环依赖中的使用,如果没有循环依赖,我们是可以省略三级缓存的。 只用一级缓存就可以进行单例的实现,
	其实发现其实使用二级缓存也能实现循环依赖的解决。即在a实例化后进行缓存,然后b初始化时使用。其实是没有问题的。之所以使用三级缓存时在aop代理对象中使用。这将在下一篇讲解。
  • 15
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值