spring源碼分析-bean的創建中的循環依賴問題

什麼是循環依賴

類似於a的構建依賴於b,而b的構建又依賴於a,按我們最直觀的理解,這就是一個永遠也解不開的環。

解決的思路

但是spring還是在單例模式下的set依賴情形下支持了循環依賴。
那麼能夠支持的最關鍵的思路是什麼勒?
假如一個bean的創建能先實例化,這樣就會得到一個bean的引用,這個引用再之後的依賴注入過程中是不會變的。那麼我們在上面a依賴b,b依賴a的問題就能得到解決了,先實例化a,然後發現依賴b,然後去實例化b,後又發現b依賴a,這個時候a的引用已經暴露,那麼就把a的引用注入到b,然後b完成它的整個生命週期,最後a在注入b,完成a的生命週期,自此,整個循環依賴的解開了

spring中的具體實現

測試條件如下
FriendA 和 FriendB是非常好的朋友,他們少了誰都得不到one piece

public class FriendA {

    private FriendB friendB;

    public FriendB getFriendB() {
        return friendB;
    }

    public void setFriendB(FriendB friendB) {
        this.friendB = friendB;
    }
}

public class FriendB {

    private FriendA friendA;

    public FriendA getFriendA() {
        return friendA;
    }

    public void setFriendA(FriendA friendA) {
        this.friendA = friendA;
    }
}

public class Start
        XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
        beanFactory.getBean("friendA");
    }
}

在分析循環依賴前,可以看一看前一篇文章bean的初始化過程

從緩存中獲取

完成循環依賴的重要節點在有兩個,一個是getBean時,第一次嘗試從緩存中獲取

		// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}

在獲取緩存的過程中會涉及三級緩存

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

這三個緩存在DefaultSingletonBeanRegistry中

bean第一次創建自然不會走到這裏面,不過我們可以注意到,上面的代碼有個條件很重要

isSingletonCurrentlyInCreation(beanName)

實例化後的處理

可以看出,只有對正在創建的單例bean纔會進入取緩存中的數據,那麼這個條件什麼時候成立勒,這就涉及到了bean創建過程中的另一個重要節點,即實例化後的處理

這裏必須搞清楚一點
實例化和初始化的區別
實例化:是指用工廠方法,或者有參構造或無參構造進行實例化
初始化:是指使用調用init-method或者調用實現了InitializingBean的鉤子方法

spring對這兩個重要的節點,都提供了拓展點

接下來我們看一看,AbstractAutowireCapableBeanFactory中的doCreateBean方法,個人認爲,最能體現bean創建過程的方法有兩個,一個是AbstractBeanFactory中的doGetBean,另一個就是此方法。對於前者的分析,請參照我前面的文章

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

可以看到先創建了一個實例化,封裝成了一個BeanWrapper,並調用getWrappedInstance,返回了引用

BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);

然後開始重要一步,即將引用作爲參數封裝成一個ObjectFactory放入了SingletonFactory

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

再之後便是屬性填充,這裏面很複雜,需要新開篇幅講,現在只說,我們的依賴就是在這裏處理的,若依賴的別的沒有創建的bean,就開始了新的getBean

populateBean(beanName, mbd, instanceWrapper);

整個過程是個遞歸的過程,理解spring中單例循環依賴的關鍵點就是上述兩個,最後附上一張圖以便理解

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章