欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring疑难解惑-循环依赖的解决

程序员文章站 2022-06-17 14:34:53
...
AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
		Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
//此处表示是否抛出早期引用,以便循环引用时使用,放在三级缓存的singtonFactories里面
//存在循环引用是采用调用ObjectFactory.getObject
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, new ObjectFactory<Object>() {
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper);
			if (exposedObject != null) {
				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) {
//此处从二级缓存的earlySingtonObjects中获取,如何不为空表示,存在循环引用
//在doGetBean方法中,会将三级缓存的singtonFactories调用ObjectFactory.getObject放入到二级缓存的earlySingtonObjects中
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
//如果相等表示,早期引用的bean(即设置到其他bean中的bean引用即为此处的早期引用)
//因为exposedObject = earlySingletonReference;最终都是一个引用
//事务代理属于此类循环引用的实例,事务代理时在AbstractAutoProxyCreater的早期引用中创建的
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
//如果能够容忍创建的bean有多个版本,则可以设置allowRawInjectionDespiteWrapping=true,但这样就破换了spring的单例原则,不建议使用
//hasDependentBean此处表示是否存在引用创建中的bean的其他bean(姑且是beanOther),如果存在则beanOther引用了bean的早期引用,与最终生成的bean是不一致的,肯定不对
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
//此处的TypeCheckOnly=true的场景暂时没有想到待补充,也请路过的博友能够指点一二
						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 " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}



DefaultSingletonBeanRegistry#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);
// 该singletonFactory不为空,在doCreateBean阶段已经放入了ObjectFactory
//此处调用getObject方法生成早期引用,并放入二级环境earlySingletonObjects
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}





AbstractAutoProxyCreator#
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
//此处this.earlyProxyReferences中放入参与早期引用的缓存,在postProcessAfterInitialization中就不用再次创建了,保证了doCreateBean中exposedObject == bean
//他们生成的代理功能本质上是一样的都是getAdvicesAndAdvisorsForBean获取的切面
//但仅限于AbstractAutoProxyCreator的子类生成的代理是可以循环引用的,例如事务属于此类
//其他类型的代理或自定义的代理可能没有实现earlyProxyReferences类似功能,导致exposed!=bean
		if (!this.earlyProxyReferences.containsKey(cacheKey)) {
			this.earlyProxyReferences.put(cacheKey, Boolean.TRUE);
		}
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.containsKey(cacheKey)) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}


1.为什么要用三级缓存而不用二级缓存
一个设计良好的系统应该不会经常出现循环引用的情况的,在一开始就设置早期引用浪费系统资源;

2.为什么三级缓存中放入ObjectFactory,而不是bean
为了扩展,生成事务代理或其他代理,以便是代理也可以循环引用


相关标签: spring 循环引用