Spring源码分析(三)(解决循环依赖)

版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37598011/article/details/90550654

    spring解决循环依赖主要通过三级缓存去完成。

	/** Cache of singleton objects: bean name --> bean instance */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

	/** Cache of singleton factories: bean name --> ObjectFactory */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

	/** Cache of early singleton objects: bean name --> bean instance */
	private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

在doGetBean中,它首先会通过getSingleton方法去尝试获取bean。

Object sharedInstance = getSingleton(beanName);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   /** 首先从singletonObjects获取bean实例 */
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
         /** 
          * 如果singletonObjects还没有此bean,有两种情况
          * 1.这个bean正在创建状态,先从earlySingletonObjects获取
          * 2.这个bean还没开始创建
          */
         singletonObject = this.earlySingletonObjects.get(beanName);
         if (singletonObject == null && allowEarlyReference) {
            /** 
             * 如果earlySingletonObjects还没有此bean,有两种情况
             * 1.说明还未被其他bean注入,正在创建状态,先从singletonFactories获取
             * 2.该bean还没开始创建
             */
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               singletonObject = singletonFactory.getObject();
               //将此bean放到提前缓存到earlySingletonObjects中
               this.earlySingletonObjects.put(beanName, singletonObject);
               //从singletonObject删除bean
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}

这个方法做了这么一件事,逐步从三级缓存中获取bean:

  1. 先到singletonObjects中获取,如果有表示实例化已经完成;
  2. 否则到earlySingletonObjects获取,如果有表示已经有bean,且存在循环依赖,将此bean作为属性注入了
  3. 否则到singletonFactories获取,如果存在循环依赖,且此属性是第一次被其他bean作为属性注入

相应的在doCreateBean中有这么一串代码:

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

		// Instantiate the bean.
		//BeanWrapper是用来持有创建出来的Bean对象的
		BeanWrapper instanceWrapper = null;
		//如果是Singleton先把缓存中同名的清除
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		//这是创建Bean的地方由createBeanInstance来完成
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
		Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
		mbd.resolvedTargetType = beanType;

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				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));
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, new ObjectFactory<Object>() {
				@Override
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}

		// Initialize the bean instance.
		//这里是对Bean的初始化,依赖注入往往在这里发生,
		// 这个exposedObject在初始化处理完后会返回作为依赖注入完成后的bean
		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) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						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;
	}

核心在这里:

		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");
			}
			addSingletonFactory(beanName, new ObjectFactory<Object>() {
				@Override
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}


	protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		synchronized (this.singletonObjects) {
			if (!this.singletonObjects.containsKey(beanName)) {
                //将beanName存放入singletonFactories中
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
	}

    这串代码会在创建bean的时候将自身注册进singletonFactories中。所以可以想象当两个bean互相依赖时,A会将自身注册进singletonFactories中,当它创建B时它可以直接从singletonFactories中获取A的引用所以B能成功创建,当B成功创建后那A也可以从singletonObjects中获取B的引用,最后A也成功创建。

总结

    Spring通过三级缓存解决了循环依赖的问题,它会在创建bean的时候将自身注册进一个singletonFactory中,然后创建它的依赖bean时会从这个缓存中获取它的引用使那个依赖bean先进行创造,最后完成自身的依赖。

举个列子:

  1. 创建A单例时,放入缓存,然后创建它的依赖B单例。
  2. 创建B单例时,发现需要依赖注入A单例,然后去加载A单例,此时从缓存中发现A单例正在创建中,于是直接从缓存得到A单例,完成自身的依赖注入。
  3. B单例依赖完成后,返回给A单例。
  4. A单例再把B单例注入到自身域中完成依赖注入。

猜你喜欢

转载自blog.csdn.net/qq_37598011/article/details/90550654