前提:允許bean提前暴露(屬性還沒有賦值,有空的類對象) ,允許循環依賴 (循環依賴才往三級緩存中添加數據)
循環依賴的情況 一 (屬性中循環依賴)
例子:
循環依賴
@Component public class CircleRefA { @Autowired private CircleRefB circleRefB; }
@Component public class CircleRefB { @Autowired private CircleRefA circleRefA; @Autowired private CircleRefC circleRefC; }
@Component public class CircleRefC { @Autowired private CircleRefA circleRefA; }
假設spring中處理順序為 CircleRefA (beanName為circleRefA ) -》 CircleRefB (beanName為circleRefB ) -》 CircleRefC (beanName為circleRefC)
先處理CircleRefA
先 getbean(circleRefA),這時一級緩存singletonObjects中沒有對應的類,且 singletonCurrentInCreation 中沒有 circleRefA , getbean(beanName) 返回 null ,調用getBean(circleRefA , ObjectFactory) 。此時先往 singletonCureentInCreation 中加入 circleRefA(表示正在創建 circleRefA 對應的實例) 。先創建一個屬性值為空的A ,稱為 早期的bean實例,調用addSingletonFactory ,往在三級緩存中添加circleRefA 對應的 ObjectFactory(此對象,就理解為時 A實例的包裝)再進行populateBean進行IOC填充circleRefA 。發現A中有CircleRefB的引用,進行CircleRefB實例化,進行 先 getbean(circleRefB)
在進行getbean(circleRefB),前面的操作一樣,后面再進行opulateBean進行IOC填充circleRefB 時,發現B中有CircleRefA的引用,進行getBean(circleRefA) (需要說明的時,屬性的編寫是認為的,此處可能先進行getBean(circleRefC),分析一樣)進行getBean(circleRefA)時,一級緩存singletonObjects中沒有對應的類,singetonCureentInCreation中有 circleRefA ;則查找二級緩存earlySingletonObjects ,沒有數據;再查找三級緩存,有數據 ,將數據填充到二級緩存earlyObjects , 刪除三級緩存,返回給B實例進行填充。發現有C類屬性,進行 getbean(circleRefC)
在進行getbean(circleRefC),前面操作同getBean(circleRefA)。后面再進行opulateBean進行IOC填充circleRefC 時,發現C中有CircleRefA的引用,進行getBean(circleRefA) 。此時getBean(circleRefA) ,是從二級緩存中拿到的數據 ,返回A對應的類。
完成 C 的實例化,一級緩存singletonObjects中添加C的實例,刪除 singletosCurrentlyInCreation中的circleRefC ,刪除三級級緩存中 circleRefC,刪除二級緩存 circleRefC。再遞歸完成 B , A的實例化(同C的實例化)。
說明:
singletonCureentInCreation 中存bean的名稱,表示實例正在創建
這里為什么有一個三級緩存singletonfactories,就是放置早期的bean實例。
為什么有一個二級緩存earlySingletonObjects,其實也是放置早期的bean實例。多次拿 早期的bean實例 這一直接沖這里面拿。
直接放在三級緩存singletonfactories 中 ,不放在earlySingletonObjects中,功能上不是也可以嗎?是的
但是,其實獲取三級緩存的方式是
源碼 :
//添加 三級緩存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { // 如果 一級緩存 中不存在 if (!this.singletonObjects.containsKey(beanName)) { // 設置 三級緩存 ,緩存 的 是 singletonFactory 對象 this.singletonFactories.put(beanName, singletonFactory); // 刪除 二級緩存 this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }
獲取三級緩存
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
singletonObject = singletonFactory.getObject();
其中
@FunctionalInterface public interface ObjectFactory<T> { /** * 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; }
三級緩存是一個包裝bean的實例的對象,singletonFactory.getObject() 是 ,其實是調用的 getEarlyBeanReference(beanName, mbd, bean) ,
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; }
這個地方就是預留了一個點位,進行操作 早期的類對象 ,將經過處理(有處理過程,可以放回原始的bean早期類對象,也可能不是,實現BeanPostProcessor接口,重寫getEarlyBeanReference就行,完全可以自定義修改) 。
就是我們說的三級緩存中,其實可以對 早期的類對象 進行自定已處理 。將處理完的對象 ,放在二級緩存中,若還有循環依賴的 處理 ,拿的是 經過處理的 早期的類對象
循環依賴的情況 二 (多例循環依賴scope 為 prototype )
往三級緩存中添加數據源碼
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, () -> getEarlyBeanReference(beanName, mbd, bean)); }
都不是單例,不會往三級緩存singletonfactories中添加數據。每次創建的都是新對象,沒必要緩存
此時根據 prototypesCurrentlyInCreation 判斷是不是再創建的 ,循環依賴的二次報錯。
創建是,會現在查
if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }
再防止 this.prototypesCurrentlyInCreation.set(beanName);
循環依賴的情況 三 (構造函數的循環依賴)
@Component public class CircleRefAA { @Autowired public CircleRefAA(CircleRefBB circleRefBB){ System.out.println("---------CircleRefAA----------"); } }
@Component public class CircleRefBB { @Lazy @Autowired public CircleRefBB(CircleRefAA circleRefAA){ System.out.println("---------CircleRefBB----------"); } }
這個時候正在創建 早期的bean實例,三級緩存中沒有存數據 ,重復向 singletonsCurrentlyInCreation 中加數據,報錯。
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }
循環依賴的情況 四 (構造函數的循環依賴加@Lazy)
網上說構造函數的循環依賴加@Lazy可以解決
--未完待續
說的比較大白話,中間的一些話語 也不是專業術語,能力有限,單大體上就是