《深入理解Spring原理》 06-Spring循环依赖问题探索

Spring循环依赖问题探索

注:本文基于Spring4.3.11.RELEASE版本Debug

注入Bean的大致流程:

AbstractApplicationContext#refresh()方法最后一步 finishBeanFactoryInitialization 会对扫描到Bean进行实例化注入。该方法主要是遍历扫描的Bean然后调用 AbstractBeanFactory#getBean()方法进行实例化Bean并注入。

实例化过程如下:

  1. 以AbstracBeanFactory#getBean()为入口开始注入某个Bean

  2. 尝试从缓存中获取Bean,若没有获取到则进行实例化并缓存

  3. 若缓存中没有取到Bean则开始实例化Bean,首先会调用 DefaultSinigletonBeanRegostry#getSingleton(beanName, singletonFactory)方法.该方法步骤大致为:

    标识当前正在创建的Bean -----》 实例化Bean ------》 取消该Bean正在创建的标识 -----》 将Bean注入到IOC中

  4. getSingleton方法首先会为当前的Bean加一个正在创建中的标识,主要体现在getSingleton方法中调用的beforeSingletonCreation(beanName)方法。主要将该beanName添加到 DefaultSingletonBeanRegistry#singletonsCurrentlyInCreation中表面该Bean正在被创建,避免并发创建

  5. 实例化Bean,这个过程比较复杂,所以只列举与本例有关的。实例化Bean时会先确定Bean的构造器,若构造器有参数则处理参数(若IOC中有参数类型的Bean直接取出来即可,否则要实例化该参数类型的Bean并注入(从第三步往后重复执行),然后赋值)后再实例化Bean。

  6. 实例化Bean完成之后,则吧singletonsCurrentlyInCreation中该bean 的标识去掉。

  7. 将实例化好的Bean注入IOC中

问题一:为什么Spring解决不了构造器循环依赖?
//构造器循环依赖案例
@Service
public class AService {
    private BService bservice;
    public  AService (BService bService) {
        this.bService = bService;
    }
}
@Service
public class BService {
    private AService aService; 
    public BService (AService aService) {
        this.aService = aService;
    }
}

如上所示是一个典型的构造器循环依赖,启动后直接报循环依赖错误.为什么setter方式的循环依赖不报错而构造器依赖就报错呢?接下来我们就仔细分析一下为什么构造器依赖会报错:

在这里插入图片描述

Spring会遍历AService和BService依次实例并注入,所以首先会实例化AService。当实例化AService时将该bean加入 singletonsCurrentlyInCreation中标识该Bean正在被创建。然后会确定AService的构造器将其实例化出来,但是构造器中有一个BService bService参数,并且判断IOC中没有此Bean然后就会调用流程中的第三步开始实例化BService(注意:此时AService还被标识正在创建)。创建BService时又会将BService放入singletonsCurrentlyInCreation中标识BService正在被创建。然后会确定BService的构造器并实例化该Bean,但是构造器中有一个AService aService参数,然后会到IOC中找aService这个bean,很显然是找不到的,然后就会去创建AService(注意:此时BService也被标识正在创建),首先会调用beforeSingletonCreation将AService标识为正在创建中(此时AService、BService都在 singletonsCurrentlyInCreation中),但是由于singletonsCurrentlyInCreation已经包含AService了,所以此时会抛出异常

protected void beforeSingletonCreation(String beanName) {//beanName : A Service
    //因为此时singletonsCurrentlyInCreation中包含 AService和BService,现在又要添加singletonsCurrentlyInCreation中添加AService将会返回false,所以会抛出异常
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

综上所述,Spring无法解决构造器循环依赖是因为相互依赖的Bean一个没有完成实例化,也就是一个构造器都没有执行成功,所以陷入了无限循环。若不是beforeSingletonCreation方法抛了异常则会陷入无限循环的状态

问题二: Spring又为什么可以解决setter循环依赖呢?

Bean的实例化过程中会调用 AbstractAutowireCapableBeanFactory#doCreateBean方法:然后调用无参构造器实例化出该Bean。若Bean满足单例Bean并且开启了允许循环依赖并且是正在创建中的Bean则调用 addSingletonFactory()方法将Bean放入第三级缓存中 singletonFactories中。在本例中就是将实例化好的AService放入三级缓存中,然后开始解析AService中的属性 bService.首先查看IOC中是否存在bService,发现不存在则开始创建BService,又因为BService也是无参构造器所以可以实例化出BService并将其放入三级缓存中。然后处理BService的属性 aService.最终会在三级缓存中获取aService,然后完成BService的注入。BService完成注入后AService也就完成了注入。

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

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
            //调用无参构造器实例化出Bean
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);

		 .....

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
         //当Bean为单例并且开启了循环依赖并且是正在创建中的Bean,才会将实例化好的Bean添加到三级缓存中。重点是单例Bean哦
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
    
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
            //调用DefaultSingletonBeanRegidtry#addSingletonFactory()方法将该Bean放入 singletonFactories第三级缓存中
			addSingletonFactory(beanName, new ObjectFactory<Object>() {
				@Override
				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);
			}
		}

	    .......
		return exposedObject;
	}
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);
			
		}
	}
总结

Spring三级缓存可以解决setter方式注入的循环依赖但是无法解决构造器循环依赖,原理就是使用Bean的无参构造器进行Bean的实例化,然后将Bean放入三级缓存中,进而解决循环依赖。

解决setter循环依赖需要满足: Bean是单例的、Spring开启了循环依赖、该Bean为当前正在创建的Bean(即singletonCurrentlyInCreation中必须包含该Bean)

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值