1. 程式人生 > >Spring之迴圈依賴解決

Spring之迴圈依賴解決

開發十年,就只剩下這套架構體系了! >>>   

概述

Spring中的迴圈依賴有兩種:構造方式和setter方式。其中構造方法的迴圈依賴是不能解決的,會直接保錯。setter方式的是通過提早暴露正在建立中的bean(未完全初始化完成)解決。

什麼叫提早暴露

我們先來看getBean()方法中最開始的地方,會從getSingleton()中獲取快取的bean例項,裡面就加入了提早暴露的邏輯。

Object sharedInstance = getSingleton(beanName);
/**
 * Return the (raw) singleton object registered under the given name.
 * <p>Checks already instantiated singletons and also allows for an early
 * reference to a currently created singleton (resolving a circular reference).
 * @param beanName the name of the bean to look for
 * @param allowEarlyReference whether early references should be created or not
 * @return the registered singleton object, or {@code null} if none found
 */
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);
}

這裡涉及到三個Map:

  • Map<String, Object> singletonObjects:已經初始化完成的bean,bean name --> bean instance;
  • Map<String, Object> earlySingletonObjects:提早暴露的bean(沒有初始化完成),bean name --> bean instance;
  • Map<String, ObjectFactory<?>> singletonFactories:通過ObjectFactory.getObject()生成提早暴露的bean

所以earlySingletonObjects、singletonFactories這兩個快取就是提早暴露的關鍵,也是Spring解決迴圈依賴的關鍵。

那這快取是什麼新增的呢?

在建立bean的時候在設定屬性之前,就將ObjectFactory加入了singletonFactories快取,這個ObjectFactory用於返回建立一半的bean。

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

/**
 * Add the given singleton factory for building the specified singleton
 * if necessary.
 * <p>To be called for eager registration of singletons, e.g. to be able to
 * resolve circular references.
 * @param beanName the name of the bean
 * @param singletonFactory the factory for the singleton object
 */
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);
		}
	}
}

PS:singletonFactories新增的時候,earlySingletonObjects移除,earlySingletonObjects新增的時候,singletonFactories