我们知道当通过构造方法的方式注入属性时,是不支持循环依赖这种场景的,本文主要通过分析源码看看为什么构造方法不能支持循环依赖。

当然,如果读者还不了解循环依赖的问题,建议先结合源码搞清楚,可以先看看这篇文章,
深入源码分析Spring如何解决循环依赖,否则很有可能看不懂本文内容。

先看问题

@Component
public class TestA {

    private final TestB testB;

    public TestA(TestB testB) {
        this.testB = testB;
    }

}
@Component
public class TestB {

    private final TestA testA;

    public TestB(TestA testA) {
        this.testA = testA;
    }
}

TestA和TestB通过构造方法互相注入依赖,结果启动报错咯!
在这里插入图片描述
进入源码分析

假设先准备实例化TestA对象,直接找到实例化关键代码部分。

				//省略部分源码。。。
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
				//省略部分源码。。。
	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				//这个方法发挥了重要的作用
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					//调用createBean方法
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					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;
					}
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

beforeSingletonCreation,上编文章分析过,把当前bean放到一个set集合中,错误就是从这抛出来的,也就是放入set集合失败了,稍微我们再来分析,第一次肯定是没问题的。

	protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

createBean方法

	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
		//省略部分源码。。。
		try {
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		//省略部分源码。。。
	}

doCreateBean 这个是核心方法,本文就关注实例化这个方法,在非构造方法依赖的情况下,这个方法是通过反射调用无参构造方法实例化的,而现在不行了。

当Spring发现有autowiring的构造函数,就会通过这个构造函数进行实例化。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
			//省略部分源码。。。
			if (instanceWrapper == null) {
			//实例化
			instanceWrapper = createBeanInstance(beanName, mbd, args);
			//省略部分源码。。。
		}
}
	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		
		//省略部分源码。。。
		
		// Candidate constructors for autowiring?
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			//有参调用这个方法
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// No special handling: simply use no-arg constructor.
		//无参构造函数是调用这个方法
		return instantiateBean(beanName, mbd);
	}

autowireConstructor

	public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
			@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
			//省略部分源码。。。
		argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
								getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
			//省略部分源码。。。
								
	}

createArgumentArray

	private ArgumentsHolder createArgumentArray(
			String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
			BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,
			boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
		//省略部分源码。。。
		try {
					Object autowiredArgument = resolveAutowiredArgument(
							methodParam, beanName, autowiredBeanNames, converter, fallback);
					args.rawArguments[paramIndex] = autowiredArgument;
					args.arguments[paramIndex] = autowiredArgument;
					args.preparedArguments[paramIndex] = autowiredArgumentMarker;
					args.resolveNecessary = true;
				}
				catch (BeansException ex) {
					throw new UnsatisfiedDependencyException(
							mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
				}
				//省略部分源码。。。
	}

resolveAutowiredArgument

	@Nullable
	protected Object resolveAutowiredArgument(MethodParameter param, String beanName,
			@Nullable Set<String> autowiredBeanNames, TypeConverter typeConverter, boolean fallback) {
			//省略部分源码。。。
		try {
			return this.beanFactory.resolveDependency(
					new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
		}
		catch (NoUniqueBeanDefinitionException ex) {
			throw ex;
		}
			//省略部分源码。。。
	}

resolveDependency这个方法在 深入源码分析Spring如何解决循环依赖 文中有看过,最终会调用到beanName的getBean方法。

源码看到这边已经足够了,我们可以看出与无参构造函数不同之处在于,依赖属性的getBean调用提前了,无参构造函数是在类实例化完成,并且放入到了三级缓存中之后才调用的,而现在不是了,也就是说现在缓存中并没有TestA。

所以当调用getBean(testB)时,同样会走到getBean(testA),此时缓存中没有testA,那么就又会反复执行testA的实例化过程,那么是在什么地方终止的呢?

就是这个方法了,此时testA要想再加入这个set集合就会返回false了,因为第一次testA的实例化过程就已经放入这个set集合了,所以此处就抛出了异常,终止了整个流程。

	protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

构造方式依赖注入
在这里插入图片描述
@Autowired属性依赖注入
在这里插入图片描述
总结

通过构造方法之所以失败的主要原因就是,依赖的属性被提前实例化了,因为testA未完成实例化,内存中也就不存在有关testA的任何记录,自然缓存中也没有,所以当再次触发testA的实例化时,也没法从缓存中获取,最终通过一个set集合判断是否被重复添加来控制,避免陷入死循环。。。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐