Spring源碼解析之從單例緩存中獲取單例bean(2)

代碼分析入口:

        Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isDebugEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

1.獲取bean

   Object sharedInstance = getSingleton(beanName) 這個方法從單例緩存中獲取bean實例:

 protected Object getSingleton(String beanName, boolean allowEarlyReference) {
     //從緩存單例中獲取緩存
     Object singletonObject = this.singletonObjects.get(beanName);
     //如果緩存bean爲空,並且bean正在創建
     if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
         synchronized (this.singletonObjects) {
             singletonObject = this.earlySingletonObjects.get(beanName);
             if (singletonObject == null && allowEarlyReference) {
                  // 從 singletonFactories 中獲取對應的 ObjectFactory
                 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  // ObjectFactory 不爲空,則創建 bean
                 if (singletonFactory != null) {
                     singletonObject = singletonFactory.getObject();
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     this.singletonFactories.remove(beanName);
                 }
             }
         }
     }
     return singletonObject;
 }

   getSingleton邏輯是很簡單的,先從singletonObjects中獲取,如果爲空並且當前bean正在創建,那麼從earlySingletonObjects中獲取。如果爲空並且允許提前創建,則從singletonFactories獲取ObjectFactory。如果不爲空則調用getObejct()創建bean,並緩存起來。分析一下三個緩存對象的作用。isSingletonCurrentlyIncreation方法主要是判斷這個bean是否處於創建過程中。

  • singletonObject:存放的是單例的bean。即beanName ---> bean實例
  • earlySingletonObjects:存放的也是單例的bean。但是earlySingletonObjects存放的是bean正在創建過程中的,在創建過程中如果bean允許提前創建則可以提前創建曝光給調用方,進而可以解決循環依賴的關鍵
  • singletonFactories:存放的是ObjectFactory。即創建單例的bean的beanFactory

以上就是從緩存中獲取bean的過程,下面繼續

如果獲取的bean不爲null,並且args爲null那麼會走進getObjectForBeanInstance方法。

protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

        // 如果是工廠類的引用 bean的name已&開頭
        if (BeanFactoryUtils.isFactoryDereference(name)) {
            if (beanInstance instanceof NullBean) {
                return beanInstance;
            }
            //如果不是FactoryBean類型 則拋出異常
            if (!(beanInstance instanceof FactoryBean)) {
                throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
            }
        }

        // 到這裏 bean是一個正常的bean 或者是一個FactoryBean
        if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
            return beanInstance;
        }

        Object object = null;
        if (mbd == null) {
            // 若 BeanDefinition 爲 null,則從緩存中加載
            object = getCachedObjectForFactoryBean(beanName);
        }
        // 若 object 依然爲空,則可以確認,beanInstance 一定是 FactoryBean
        if (object == null) {
            // Return bean instance from factory.
            FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
            // Caches object obtained from FactoryBean if it is a singleton.
            if (mbd == null && containsBeanDefinition(beanName)) {
                //類型轉換
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            boolean synthetic = (mbd != null && mbd.isSynthetic());
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }

該方法的核心其實是getObjectFromFactoryBean方法。之前的方法主要還是進行校驗的:

  • 如果bean的實例已&開頭,不是FactoryBean直接拋出異常,如果是NullBean直接返回。
  • 如果bean不是FactoryBean,或者已&開頭,返回對應實例。
  • 如果 BeanDefinition 爲空,則從 factoryBeanObjectCache 中加載,如果還是空,則可以斷定 beanInstance 一定是 FactoryBean 類型,則委託 getObjectFromFactoryBean() 方法處理。

getObjectFromFactoryBean方法主要是獲取指定的bean的實例對象。對於FactoryBean類型的bean則委託給FactoryBeanRegistrySupport執行getObjectFromFactoryBean獲取對應的實例對象。

 //這個方法全局是在確定bean要確定是全局單例的。 
        protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
        //判斷是單例並且這個bean是存在的
        if (factory.isSingleton() && containsSingleton(beanName)) {
            synchronized (getSingletonMutex()) {
                //獲取緩存中指定的factoryBean
                Object object = this.factoryBeanObjectCache.get(beanName);
                if (object == null) {
                    // 爲空,則從 FactoryBean 中獲取對象
                    object = doGetObjectFromFactoryBean(factory, beanName);
                    
                    Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                    if (alreadyThere != null) {
                        object = alreadyThere;
                    }
                    else {
                        if (shouldPostProcess) {
                            if (isSingletonCurrentlyInCreation(beanName)) {
                                // Temporarily return non-post-processed object, not storing it yet..
                                return object;
                            }
                            //前置處理
                            beforeSingletonCreation(beanName);
                            try {
                                object = postProcessObjectFromFactoryBean(object, beanName);
                            }
                            catch (Throwable ex) {
                                throw new BeanCreationException(beanName,
                                        "Post-processing of FactoryBean's singleton object failed", ex);
                            }
                            finally {
                                //後置處理
                                afterSingletonCreation(beanName);
                            }
                        }
                        if (containsSingleton(beanName)) {
                            this.factoryBeanObjectCache.put(beanName, object);
                        }
                    }
                }
                return object;
            }
        }
        else {
            //非單例模式獲取
            Object object = doGetObjectFromFactoryBean(factory, beanName);
            if (shouldPostProcess) {
                try {
                    object = postProcessObjectFromFactoryBean(object, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
                }
            }
            return object;
        }
    }
  • 若爲單例且單例 bean 緩存中存在 beanName,則進行後續處理(跳轉到下一步),否則則從 FactoryBean 中獲取 bean 實例對象,如果接受後置處理,則調用 postProcessObjectFromFactoryBean() 進行後置處理。
  • 首先獲取鎖(其實我們在前面篇幅中發現了大量的同步鎖,鎖住的對象都是 this.singletonObjects, 主要是因爲在單例模式中必須要保證全局唯一),然後從 factoryBeanObjectCache 緩存中獲取實例對象 object,若 object 爲空,則調用 doGetObjectFromFactoryBean() 方法從 FactoryBean 獲取對象,其實內部就是調用 FactoryBean.getObject()
  • 如果需要後續處理,則進行進一步處理,步驟如下:
    • 若該 bean 處於創建中(isSingletonCurrentlyInCreation),則返回非處理對象,而不是存儲它
    • 調用 beforeSingletonCreation() 進行創建之前的處理。默認實現將該 bean 標誌爲當前創建的。
    • 調用 postProcessObjectFromFactoryBean() 對從 FactoryBean 獲取的 bean 實例對象進行後置處理,默認實現是按照原樣直接返回,具體實現是在 AbstractAutowireCapableBeanFactory 中實現的,當然子類也可以重寫它,比如應用後置處理
    • 調用 afterSingletonCreation() 進行創建 bean 之後的處理,默認實現是將該 bean 標記爲不再在創建中。
  • 最後加入到 FactoryBeans 緩存中。

 

當中最重要的三個方法 beforeSingletonCreation(),postProcessObjectFromFactoryBean() ,afterSingletonCreation() 。

  • beforeSingletonCreation()方法:
protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

主要是講即將要創建的bean緩存在singletonsCurrentlyInCreation表明這個bean正在創建。

  • afterSingletonCreation()方法:
protected void afterSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
			throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
		}
	}

主要是講即將要創建完畢的bean從singletonsCurrentlyInCreation中移除,表明這個bean已經創建完畢。

  • postProcessObjectFromFactoryBean()方法

postProcessObjectFromFactoryBean是對bean實例對象進行後置處理。其實現類AbstractAutowireCapableBeanFactory進行應用的後置通知並返回bean實例。這個之後爲專門分析。

這篇博文分析了緩存中獲取bean對象的處理過程。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章