Spring中构造方法中产生循环依赖注入失败问题

Spring中构造方法中产生循环依赖注入失败问题,第1张

一、简单聊一聊bean的生命周期 1.1、名词讲解

springfactory中的三级缓存

singletonObjects【一级】、earlySingletonObjects【二级】、singletonFactories【三级】

三级缓存分别作用:

一级:存储经历过完整bean的生命周期后的对象

二级:在属性注入情况下存在循环依赖情况,保证对象的单例

三级:打破循环依赖,其内部存储为bean名称+普通对象

1.2、案例分析

假设有三个类A、B、C

生命A对象生命周期

1、根据构造方法反射生成未初始化对象A —>并将生成的对象存储到三级缓存singletonFactories中

2、属性填充B(B不存在对A的属性依赖)

3、属性填充完毕后执行:aware相关接口、初始化前、初始化、初始化后(可能执行aop生成代理对象)

4、将执行完生命周期后的bean存放到singletonObjects中

1.3、核心代码分析
//AbstractAutowireCapableBeanFactory.doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		// 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.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		//。。。。
		//作为判断依据为存放三级缓存
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			//将未初始化的bean对象存放到三级缓存中,存储的未beanName + lambda表达式
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

         //最终生成对象bean
		Object exposedObject = bean;
		try {
			//对象属性填充
			populateBean(beanName, mbd, instanceWrapper);
			//属性填充完毕后执行:aware相关接口、初始化前、初始化、初始化后(可能执行aop生成代理对象)
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			//。。。。
		}

    	//正常情况下earlySingletonExposure==true
		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
                  //相等说明未进行aop *** 作
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						//。。。。
				}
			}
		}

		// 主要包含注册 destroy method
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			//。。。
		}

    	//返回最终对象bean,两种情况:aop之后的代理bean、普通bean
		return exposedObject;
	}
二、为什么会存在构造方法注入属性时存在循环依赖报错
@Component
class A {
    private B b;
    private C c;
    
    public A(B b,C c){...}
}
@Component
class B {
    @Autowired
    private A a;
}
@Component
class C {
    @Autowired
    private A a;
}

案例分析:

1、初始化生成A对象时发现内部仅有一个有参构造方法,故选择其进行class反射,故去ioc容器中寻找B、C的对象进行属性注入。但请注意在该过程中还未生成A的初始化前对象,也就是说初始化前的对象A还未存储对第三级缓存中。

2、在ioc容器中寻找B、C时发现其还未创建。故通过空构造方法进行构造对象b、c。紧接着进行属性注入A,但在ioc容器中发现其不存在,故又进入创建A对象,beforeSingletonCreation方法中报错。

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

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/720031.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存