Spring之迴圈依賴解決
阿新 • • 發佈:2019-04-08
概述
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