spring 解决循环依赖

在 spring 框架中,我们知道它是通过三级缓存来解决循环依赖的,那么它具体是怎么实现的,以及是否必须需要三级缓存才能解决循环依赖,本文来作相关介绍。

具体实现

先来看看它的三级缓存到底是什么,先看如下代码:

// DefaultSingletonBeanRegistry
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;
}
  • 一级缓存:singletonObjects
  • 二级缓存:earlySingletonObjects
  • 三级缓存:singletonFactories

获取实例对象的时候,先去一二级缓存查找,如果没找到,allowEarlyReference 为 true,会对 singletonObjects 加锁,并进行二次查找,还是找不到,会通过三级缓存,获取一个 singletonFactory,通过 singletonFactory 获取实例对象。

下面来看看这个 singletonFactory 是什么?

在 AbstractAutowireCapableBeanFactory#doCreateBean 中有这么一段代码:

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");
	}
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
	Assert.notNull(singletonFactory, "Singleton factory must not be null");
	synchronized (this.singletonObjects) {
		if (!this.singletonObjects.containsKey(beanName)) {
			this.singletonFactories.put(beanName, singletonFactory);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}
}

放入了一个 lambda 表达式,即在实例化完一个实例对象之后,将这个半成品通过 singletonFactory 提前暴露出去,接着再进行 populateBean、applyPropertyValues 调用。

实例对象创建过程

下面来看看实例对象创建时的具体过程 ,如上图所示,A 引用 B,B 引用 A。

实例化完 A 之后,将 A 提前暴露,接着进行属性填充,此时发现需要 B,而 B 还未创建,接着去创建 B,实例化完 B 之后,也将 B 暴露出去,接着进行属性填充,此时需要 A,接着去找 A,由于 A 已经提前暴露了,会获取到 singletonFactory,接着调入 getEarlyBeanReference。

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
	Object exposedObject = bean;
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
			exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
		}
	}
	return exposedObject;
}

存在 SmartInstantiationAwareBeanPostProcessor 接口子类时,调用对应实现的 getEarlyBeanReference,主要是 AOP 增强时使用。

// AbstractAutoProxyCreator
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
	Object cacheKey = getCacheKey(bean.getClass(), beanName);
	this.earlyProxyReferences.put(cacheKey, bean);
	return wrapIfNecessary(bean, beanName, cacheKey);
}

将实例化后的半成品放入 earlyProxyReferences,接着对其进行包装,即 AOP增强。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}
	if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
		return bean;
	}
	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	// Create proxy if we have advice.
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
	if (specificInterceptors != DO_NOT_PROXY) {
		this.advisedBeans.put(cacheKey, Boolean.TRUE); // 需要拦截,标记
		Object proxy = createProxy(
				bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
		this.proxyTypes.put(cacheKey, proxy.getClass());
		return proxy;
	}

	this.advisedBeans.put(cacheKey, Boolean.FALSE); // 不需要拦截,标记
	return bean;
}

如果 A 中的方法需要增强,getAdvicesAndAdvisorForBean 方法会遍历注册的 beanDefinitionNames,找到匹配的 advisorNames,接着遍历 advisorsNames,创建对应的 advisor,填充属性需要 advice,进行 advice 的创建,最终完成 advisor 的创建,此时创建的 advisor 只是候选,具体能否为当前 A 使用,还需进行匹配判断,最后将匹配的 advisor 返回,即 specificInterceptors,接着对 A 进行标记,创建 proxy 返回。

返回的 proxy 会放入二级缓存 earlySingletonObjects,并将三级缓存中的 singletonFactory 删除。

拿到对这个半成品创建的 proxy,完成 B 的属性填充,接着进行 B 的初始化,如果 B 也需要 AOP 增强,执行 AbstractAutoProxyCreator#postProcessAfterInitialization。

// AbstractAutoProxyCreator
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

最后返回的就是增强后的 B,接着将 B 填充进 A,完成 A 的属性填充。进行 A 的初始化,此时调用 postProcessAfterInitialization 传入的参数 bean 还是一开始实例化的 bean,并不是创建 B 时增强的 proxyA,从 earlyProxyReferences 移除后与传入的参数 bean 相等,不会进行二次增强。

现在有一个问题,出现了两个 A,一个是普通的 A,一个是增强后的 proxyA,接着看看 spring 中的处理。

if (earlySingletonExposure) {
	Object earlySingletonReference = getSingleton(beanName, false);
	if (earlySingletonReference != null) {
		if (exposedObject == bean) {
			exposedObject = earlySingletonReference;
		}
	}
}

通过 getSingleton 再获取一次,此时会从二级缓存获取到增强后的 proxyA,接着判断成立,会将proxyA 作为 exposedObject 返回,并将其注册到一级缓存 singletonObjects。

现在,我们可以知道每个缓存里存放的具体是什么了:

  • 一级缓存 singletonObjects:完全的单例对象
  • 二级缓存 earlySingletonObjects:半成品的 AOP 的增强对象
  • 三级缓存 singletonFactories:获取半成品对象 或着 生成半成品 AOP 增强的工厂方法

由此可知,解决循环依赖,并不是必须需要三级缓存,如果没有 AOP 增强,只采用 singletonObjects 和 singletonFactories 两级缓存就可以解决循环依赖。而二级缓存 earlySingletonObjects,专为解决 AOP 而存在。

并且,对于A,返回 proxyA,对于 B,填充的就是 proxyA,而 proxyA 又是 A 子类,这样 proxyA 也就拥有了 A 中填充的属性。即 proxyA 只是对方法进行增强,而属性填充还是在 A 中进行。这样也体现了类的单一职责原则。

相关推荐

  1. Spring如何解决循环依赖

    2024-06-06 07:48:11       21 阅读
  2. Spring如何解决循环依赖

    2024-06-06 07:48:11       17 阅读
  3. spring循环依赖解决方案

    2024-06-06 07:48:11       13 阅读
  4. Spring如何解决循环依赖

    2024-06-06 07:48:11       9 阅读
  5. sping怎么解决循环依赖

    2024-06-06 07:48:11       6 阅读
  6. Spring循环依赖问题如何解决

    2024-06-06 07:48:11       14 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-06 07:48:11       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-06 07:48:11       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-06 07:48:11       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-06 07:48:11       18 阅读

热门阅读

  1. Django中间件

    2024-06-06 07:48:11       5 阅读
  2. Python环境与编辑器:探索编程世界的双翼

    2024-06-06 07:48:11       11 阅读
  3. Flink 入门案例介绍

    2024-06-06 07:48:11       6 阅读
  4. 论文阅读:Fast Neural Scene Flow

    2024-06-06 07:48:11       7 阅读
  5. Openstack学习(1)——架构

    2024-06-06 07:48:11       6 阅读
  6. 022、键管理_遍历键

    2024-06-06 07:48:11       6 阅读
  7. Pspark从hive读数据写到Pgsql数据库

    2024-06-06 07:48:11       8 阅读