循環依賴指多個對象的建立過程當中均須要注入對方對象,以下所示java
class A{ B b; public A(){ } public A(B b){ this.b = b; } public void setB(B b){ this.b = b; } }
class B{ A a; public B(){ } public B(A a){ this.a = a; } public void setA(A a){ this.a = a; } }
Spring中將對象建立分爲以下兩步面試
而且引入三級緩存,來提早暴露對象引用,從而解決循環依賴的問題spring
假設A和B的建立中,field均須要對方的引用,在refresh方法進行到finishBeanFactoryInitialization(beanFactory)時,會開始建立非懶加載的singleton,這裏會先進入preInstantiateSingletons方法,根據beanName調用getBean方法,假設此時A先進行建立,那麼會進入下面方法segmentfault
doGetBean
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean緩存
getSingleton---1ide
@Override @Nullable public Object getSingleton(String beanName) { return getSingleton(beanName, true); } @Nullable 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; }
首先調用上面方法先從singletonObjects中場是獲取,發現爲null,因爲isSingletonCurrentlyInCreation爲false(對象未在建立過程當中),所以直接返回nullpost
if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
其中執行DefaultSingletonBeanRegistry#getSingleton(beanName,ObjectFactory)方法簡化版以下,傳入的ObjectFactory實現類是一個lambda表達式,也即用createBean方法重寫ObjectFactory#getObject方法this
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { boolean newSingleton = false; try { singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { } } catch (BeanCreationException ex) { } finally { } if (newSingleton) { addSingleton(beanName, singletonObject); } } return singletonObject; } }
這裏第一行調用singletonFactory.getObject方法會觸發createBean,又觸發AbstractAutowireCapableBeanFactory#doCreateBean方法中主題步驟以下.net
實例化bean代理
將bean放入三級緩存singletonFactories
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); }
其中調用addSingletonFactory方法以下,此處傳入的lambda表達式給定的即爲ObjectFactory對象,在執行其getObject方法時,即執行getEarlyBeanReference
方法(這裏須要留意!)
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); } } }
A執行populateBean,開始注入屬性b,因爲B的對象還未建立,getSingleton---1(b)爲null,這時觸發B對象建立
B進行實例化
B放入三級緩存
B執行populateBean,開始注入屬性a,調用getSingleton---1方法獲取a,發現一級緩存singletonObject中沒有對應對象,且正在建立中,則從二級緩存earlySingletonObjects中獲取,發現仍然爲null且allowEarlyReference默認爲true,則去三級緩存中去獲取,最終從三級緩存中獲取,因爲放入三級緩存時,lambda表達式爲() -> getEarlyBeanReference(beanName, mbd, bean),因此會調用getEarlyBeanReference方法以下
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); } } } return exposedObject; }
這裏在遍歷後置處理器的過程當中,會調用到AbstractAutoProxyCreator的postProcessAfterInitialization方法,此方法會判斷A是否被代理,若是被代理會建立代理對象並返回,以後將原有A對象從三級緩存中刪除,並將A的代理對象加入到二級緩存earlySingletonObjects中,以後將A的代理對象注入給B
B執行initializeBean方法,調用後置處理器及afterProperties方法,這裏提到後置處理器,一樣會判斷B是否被代理,若是被代理則會建立B的代理對象並返回
B建立結束以後,會回到getSingleton---2方法,調用addSingleton(beanName, singletonObject);方法,以下
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
這裏會將B從三級緩存中刪除,並加入到一級緩存中
將B建立好的對象注入到A中
A執行initializeBean方法,進行初始化,初始化完成
回到getSingleton--2,執行DefaultSingletonBeanRegistry#addSingleton
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
將A從二級緩存中刪除,並加入到一級緩存中
從上面步驟能夠看出,
三級緩存分別用於存放下面三類對象
一級緩存singletonObjects
徹底建立好的對象,若是被代理,則存放代理對象
二級緩存earlySingletonObjects
未徹底建立好的代理對象
三級緩存singletonFactories
只進行了實例化,未進行屬性注入和初始化的對象
爲什麼上面機制生效
因爲提早暴露了A對象的引用!,於是在B注入好不完整的A對象後,B覺得本身建立好了,這時會注入給A,同時A也會將此B對象看成建立好的,並注入給本身,這樣A就真建立完成了,因爲B保留着A的引用,這樣B也就真建立完成了
如上在有循環依賴的狀況下,假設A被代理,那麼須要將A的代理對象注入給B,這時經過getSingleton方法從三級緩存獲取對象的過程當中,因爲ObjectFactory的getObject方法被重寫爲AbstractAutowireCapableBeanFactory#getEarlyBeanReference方法,這時會觸發後置處理器的執行,會調用AbstractAutoProxyCreator的postProcessAfterInitialization方法,並返回代理對象,以後將代理對象返回用於注入,並放入二級緩存,若是A和除了B的其餘對象也構成循環依賴,以後直接從二級緩存中獲取A的代理對象便可
在沒有循環依賴的狀況下,不會使用到二級緩存,若是A被代理,那麼A會在徹底建立後,在調用後置處理器序列時,會調用AbstractAutoProxyCreator的postProcessAfterInitialization方法,並返回代理對象
從上能夠看出,
Spring循環依賴三級緩存是否能夠減小爲二級緩存? - SegmentFault 思否