spring源碼解決循環引用思想


開發過程中,經常存在類似於A->B,B->A的情況;詳見spring源碼 DefaultSingletonBeanRegistry的

getSingleton(String beanName, boolean allowEarlyReference)方法:
/**
	 * spring循環引用的處理思路: 允許提前執行引用當前創建的單例對象,
	 * 此時提前引用的單例對象的屬性注入還未完成,因此可以解決循環引用的問題
	 * 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
	 */
	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 先從單例緩存中找,沒有找到會先判斷是否是正在創建的bean
		// isSingletonCurrentlyInCreation 判斷對應的單例對象是否在創建中
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				// earlySingletonObjects中保存所有提前曝光的單例,嘗試從earlySingletonObjects中找
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					// 如果允許早期依賴,可以嘗試從singletonFactories中找到對應的單例工廠
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						//創建bean,並緩存提前曝光的bean,就是還未進行屬性注入的bean,用於解決循環依賴
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

  

說明:

  

	/** Cache of singleton objects: bean name to bean instance. */
	/** 緩存單例bean */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** Cache of singleton factories: bean name to ObjectFactory. */
	/** 緩存單例工廠 */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** Cache of early singleton objects: bean name to bean instance. */
	/** 緩存提前曝光的單例bean 即還未完成屬性注入的bean */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

	/** Set of registered singletons, containing the bean names in registration order. */
	private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

 

ObjectFactory 接口的getObject()方法:

public interface ObjectFactory<T> {

	/**
	 * 此方法返回被bean工廠管理的bean的實例
	 * Return an instance (possibly shared or independent)
	 * of the object managed by this factory.
	 * @return the resulting instance
	 * @throws BeansException in case of creation errors
	 */
	T getObject() throws BeansException;

}

 

@Component
public  class A {
	@Autowired
	private B b;
	
}

@Component
public class B {

	@Autowired
	private A a;
}

 1、首先創建A的實例a,然后對a做屬性填充B

 2、此時發現需要創建B的實例b,創建實例b,

 3、對b做屬性填充,發現需要A的實例;此時A的實例對象a正在創建中,此時B的對象b會設置屬性A a=null;以用來完成B的實例化成功 

 4、B實例化對象b完成;設置A實例化對象a的b屬性;完成a的實例化;

 

  

 

 

循環引用的解決方案:

    1 使用@Autowired 注解,由spring決定對象屬性的注入時機,先暴露對象A的引用,在需要的時候在注入對象B;

    2  基於setter方法注入屬性B


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM