Spring之為什么要用三級緩存


  剛才看了手機上的公眾號,看到一個問題,Spring為什么會有三級緩存,只用兩級緩存行不行

  結論當然是不行,畢竟做Spring的又不是傻蛋,大師考慮問題那可是很深遠的

  在AbstractAutowireCapableBeanFactory # doCreateBean 方法中,實例化一個bean之后,填充屬性值之前,會把該bean放到三級緩存中

addSingletonFactory(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });

  AbstractAutowireCapableBeanFactory # getEarlyBeanReference

這段代碼是中getEarlyBeanReference方法作用是AOP

       AbstractAutoProxyCreator就實現了這個方法

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                    if (exposedObject == null) {
                        return null;
                    }
                }
            }
        }
        return exposedObject;
    }

  這里對於一個bean如果應該動態代理就創建代理,如果是普通對象就直接返回普通對象

  如果此時有循環依賴,進一步假設這個bean是應該進行動態代理的,那么在B獲取A的時候,就會調用這個  getEarlyBeanReference ,並且清除三級緩存,並放入二級緩存

  我們再往下看,看  AbstractAutowireCapableBeanFactory.doCreateBean 中的568行

if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {//如果從一級緩存或二級緩存里取得出來的話,把緩存中的bean返回,保證是同一個對象 if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }

  注意那個false入參

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);//由於入參是false,下面的邏輯不會走,只會在二級緩存里取 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);
    }

  =============2021-09-02=============

  AbstractAutowireCapableBeanFactory 

    // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);//填充屬性,會發生循環依賴 @1
            exposedObject = initializeBean(beanName, exposedObject, mbd);//這里有后置處理器beanPostProcessor,可能會進行aop @2
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {//相等
                    exposedObject = earlySingletonReference;
                }

  再來理一下思路,假設當前正在創建beanA,beanA依賴beanB,beanB也依賴beanA。

  當在實例化BeanA之后,會接着執行populateBean會填充beanB。結果beanB發現自己也需要依賴beanA,此時就會觸發三級緩存中的factory方法。如果beanA剛好要進行aop,那么在beanB的實例化過程中,由於beanB依賴了beanA,beanA就會提前進行aop,然后將beanA從三級緩存中清掉,再將beanA放入二級緩存。

  在@2處,進行aop之前會判斷該beanName是否已經進行過aop,所以這個beanA不會再次被增強。

   Object earlySingletonReference = getSingleton(beanName, false); 第二個參數是false,只會從一級和二級緩存中取。如果beanA被beanB循環依賴,且經過aop,那么beanA肯定在二級緩存。所以 earlySingletonReference != null 為true。

  由於在循環依賴中已經經過了aop,所以 exposedObject == bean 為true

  所以對 exposedObject 賦值,保證最終拿到的bean是經過了aop的beanA。

  

  如果真的有循環依賴,那么這個bean一定會從三級緩存進入二級緩存,如果這個bean剛好是要被AOP的,那么就一定要保證bean的單例性。所以在最終返回bean之前,檢查二級緩存里有沒有該對象,如果有就一定要用緩存里的對象。如果沒有循環依賴,那么這個bean肯定在三級緩存里呆着呢,這里由於入參是false。也不會去三級緩存里拿。

Object earlySingletonReference = getSingleton(beanName, false);

  那么這里earlySingletonReference 就是 null,beanA的值就是開始進行實例化的beanA。

結論

  只有兩級緩存行不行呢?沒有aop是可以的,有aop的話就不行了。

  


免責聲明!

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



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