Spring source code analysis (c) (to resolve circular dependencies)

Copyright Notice: Copyright: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/qq_37598011/article/details/90550654

    spring to resolve circular dependencies mainly through three cache to complete.

	/** 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);

In doGetBean, which will first attempt by getSingleton way to get 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;
}

The way to do such a thing, and gradually get three bean from the cache:

  1. First singletonObjects acquired, indicating if instantiated has been completed;
  2. Otherwise earlySingletonObjects to get, if there is already represented bean, and there is a circular dependency, this bean injected as a property
  3. Otherwise singletonFactories to obtain, if there is a circular dependency, and this property is the first time the other properties as bean injection

There are so appropriate in a string of code 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;
	}

The core here:

		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);
			}
		}
	}

    This string of code when creating the bean itself into singletonFactories in registration. So imagine when two bean rely on each other, A will register itself into singletonFactories, it can get when it creates B directly from singletonFactories in so B can successfully create a reference of A, B when A is successfully created that can be get a reference from singletonObjects B, and finally a successfully created.

to sum up

    Spring solve the problem through three cache cycle dependent, it will be created when the bean will be registered into a singletonFactory in itself, then create it depends bean will get from this cache when it makes a reference to the bean to be dependent on the creation of finalize their dependence.

For Liezi:

  1. When creating a single embodiment A, into the cache, and then create it depends Singleton B.
  2. When creating a single embodiment B, A single injection was found to rely embodiment, a single case and then to load A, this time from the discovery cache A single embodiment being created, thereby obtaining a single embodiment A directly from the cache, complete its dependency injection.
  3. After completion dependent B single embodiment, A is returned to a single embodiment.
  4. A single B Example singleton then injected into the completion own domain dependency injection.

Guess you like

Origin blog.csdn.net/qq_37598011/article/details/90550654