一起康康Spring源码如何对循环依赖进行处理

循环依赖

    • 1. 构造器循环依赖
    • 2. setter循环依赖
      • 2.1 首先分析几个缓存分别产生数据的地方
      • 2.2 获取单例缓存的地方
      • 3.Spring解决循环依赖的流程(借鉴Spring源码深度解析第二版)
      • 4. 总结

1. 构造器循环依赖

此依赖无法解决,只能抛出异常表示循环依赖。因为使用构造器产生的循环依赖会造成一个环,比如创建A,A构造器需要B,那么创建B,B构造器又需要C,那么创建C,C构造器又需要A,从而导致死循环构造对象。
一起康康Spring源码如何对循环依赖进行处理_第1张图片

2. setter循环依赖

以两个对象构成的循环依赖为例进行分析。

Spring解决循环依赖使用了以下三个Map进行存储。两个set集合进行辅助处理。

	/**用于存放BeanName和创建bean实例(instance)之间的关系 */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** 用于存放BeanName和 创建bean工厂 (FactoryBean)之间的关系 */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** 用于存放创建的原始bean的一个引,即使用工厂方法或构造方法创建出来的对象,一旦对象最终创建好,此引用信息将remove掉 */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
	
	/** 用于存放已加载的beanName */
	private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
	
	/** 用于存放正在创建的beanName */
	private final Set<String> singletonsCurrentlyInCreation =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));

2.1 首先分析几个缓存分别产生数据的地方

  1. 创建bean,在bean实例化之后,初始化之前singletonFactories缓存有数据。此时singletonObjects 、earlySingletonObjects、registeredSingletons缓存对应的beanName为空。
	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			//1. bean的实例化
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		
		synchronized (mbd.postProcessingLock) {
		// 2. 满足循环依赖的条件是 :单例 && 允许循环依赖 && 当前bean正在创建
			boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
			
			if (earlySingletonExposure) {
				//3.初始化完成前创建beanName与FactoryBean的缓存
				addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
			}
			// 3. 属性注入
			populateBean(beanName, mbd, instanceWrapper);
			
			// 4. bean的初始化,调用initmethod
			exposedObject = initializeBean(beanName, exposedObject, mbd);

		return exposedObject;
	}
	protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		synchronized (this.singletonObjects) {
			if (!this.singletonObjects.containsKey(beanName)) {
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
	}
  1. 简化获取单例步骤,保留核心代码。
    在获取单例后,此时singletonObjects有缓存数据、registeredSingletons有相应的beanName注册信息,singletonFactories,earlySingletonObjects缓存对应的beanName为空。
	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		synchronized (this.singletonObjects) {
			//1.判断bean是否加载,bean最后存放在singletonObjects缓存中。
			Object singletonObject = this.singletonObjects.get(beanName);
			//2. 有缓存直接返回,否则获取bean对象
			if (singletonObject == null) {
				//3. 将beanName添加进Set 集合 singletonsCurrentlyInCreation中
				beforeSingletonCreation(beanName);
				//4. 获取初始化bean,该bean是步骤一createBean中的对象
				singletonObject = singletonFactory.getObject();
				//5. 将beanName从Set集合 singletonsCurrentlyInCreation中移除
				afterSingletonCreation(beanName);
				//6. 加入缓存
				addSingleton(beanName, singletonObject);

			}
			return singletonObject;
		}
	}
	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			//创建完bean之后只保存在singletonObjects中
			this.singletonObjects.put(beanName, singletonObject);
			//删除其他缓存singletonFactories,earlySingletonObjects
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			//保存加载完的beanName信息
			this.registeredSingletons.add(beanName);
		}
	}

2.2 获取单例缓存的地方

  1. 最开始调用doGetBean地方获取缓存信息。一起康康Spring源码如何对循环依赖进行处理_第2张图片
    分析getSingleton方法
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	//1.首先从缓存singletonObjects中取,如果不为空则直接返回。
	//因为在bean的初始化之后bean的相关信息会加入到singletonObjects缓存中,earlySingletonObjects,singletonFactories为空
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
			//2.如果singletonObject 为空 && bean 正在创建,则尝试从earlySingletonObjects获取
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
				//3.earlySingletonObjects为空则从singletonFactories中获取
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						//4.将ObjectFactory 存放在earlySingletonObjects缓存中。
						this.earlySingletonObjects.put(beanName, singletonObject);
						//5.移除 singletonFactories 缓存
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}
  1. doCreateBean中获取
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {	
		.....省略无关代码....	
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper);
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		
		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			//1.  earlySingletonReference 不为空则说明存在循环依赖,
			//因为当创建A时要填充B时,此时A的singletonFactories有数据,然后转去创建B。
			//当B创建完之后要填充A时去缓存getSingleton(beanName,true)拿A缓存这时删除了singletonFactories缓存,
			//添加了earlySingletonObjects缓存,那么下次A填充完B之后执行这里时就有了缓存,
			//则说明存在循环依赖
			if (earlySingletonReference != null) {
				//2. 如果相等则说明exposedObject没有在初始化之后被增强
				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) {
					//3. 依赖检测
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					//4. 不为空则说明当前bean创建后其依赖的bean还没有创建完,存在循环依赖,直接抛异常。
					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 " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}
		.....省略无关代码....	
		return exposedObject;
	}

3.Spring解决循环依赖的流程(借鉴Spring源码深度解析第二版)

一起康康Spring源码如何对循环依赖进行处理_第3张图片

4. 总结

假如有两个对象A,B形成了循环依赖,在创建A时,也就是执行createBeanInstance之后,populateBean执行之前,这时通过addSingletonFactory()方法将ObjectFactory信息存放在了singletonFactories缓存中。接下来执行populateBean,检测到要填充的属性为对象beanB时则转向去创建B,当执行到B的populateBean时检测要填充属性对象A,而A已经存在于singletonFactories缓存中,所以B持有未填充属性的A对象,在A填充完了B之后继续填充A属性,因为B持有的A对象的地址与A对象地址一致,所以在A继续执行populateBean后B中持有的也是一致的。这就解决了循环依赖的问题。

你可能感兴趣的:(Spring)