概述
前面我們已經分析了spring對於xml配置檔案的解析,將分析的資訊組裝成 BeanDefinition,並將其儲存註冊到相應的 BeanDefinitionRegistry 中。至此,Spring IOC 的初始化工作完成。接下來我們將對bean的載入進行探索。
之前系列文章:
spring原始碼深度解析— IOC 之 預設標籤解析(上)
spring原始碼深度解析— IOC 之 預設標籤解析(下)
BeanFactory
當我們顯示或者隱式地呼叫 getBean()
時,則會觸發載入 bean 階段。如下:
public class AppTest { @Test public void MyTestBeanTest() { BeanFactory bf = new XmlBeanFactory( new ClassPathResource("spring-config.xml")); MyTestBean myTestBean = (MyTestBean) bf.getBean("myTestBean"); } }
我們看到這個方法是在介面BeanFactory中定義的,我們看下BeanFactory體系結構,如下圖所示:
從上圖我們看到:
(1)BeanFactory作為一個主介面不繼承任何介面,暫且稱為一級介面。
(2)有3個子介面繼承了它,進行功能上的增強。這3個子介面稱為二級介面。
(3)ConfigurableBeanFactory可以被稱為三級介面,對二級介面HierarchicalBeanFactory進行了再次增強,它還繼承了另一個外來的介面SingletonBeanRegistry
(4)ConfigurableListableBeanFactory是一個更強大的介面,繼承了上述的所有介面,無所不包,稱為四級介面。(這4級介面是BeanFactory的基本介面體系。繼續,下面是繼承關係的2個抽象類和2個實現類:)
(5)AbstractBeanFactory作為一個抽象類,實現了三級介面ConfigurableBeanFactory大部分功能。
(6)AbstractAutowireCapableBeanFactory同樣是抽象類,繼承自AbstractBeanFactory,並額外實現了二級介面AutowireCapableBeanFactory
(7)DefaultListableBeanFactory繼承自AbstractAutowireCapableBeanFactory,實現了最強大的四級介面ConfigurableListableBeanFactory,並實現了一個外來介面BeanDefinitionRegistry,它並非抽象類。
(8)最後是最強大的XmlBeanFactory,繼承自DefaultListableBeanFactory,重寫了一些功能,使自己更強大。
定義
BeanFactory,以Factory結尾,表示它是一個工廠類(介面), 它負責生產和管理bean的一個工廠。在Spring中,BeanFactory是IOC容器的核心介面,它的職責包括:例項化、定位、配置應用程式中的物件及建立這些物件間的依賴。BeanFactory只是個介面,並不是IOC容器的具體實現,但是Spring容器給出了很多種實現,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一個,該實現將以XML方式描述組成應用的物件及物件間的依賴關係。XmlBeanFactory類將持有此XML配置後設資料,並用它來構建一個完全可配置的系統或應用。
BeanFactory是Spring IOC容器的鼻祖,是IOC容器的基礎介面,所有的容器都是從它這裡繼承實現而來。可見其地位。BeanFactory提供了最基本的IOC容器的功能,即所有的容器至少需要實現的標準。
XmlBeanFactory,只是提供了最基本的IOC容器的功能。而且XMLBeanFactory,繼承自DefaultListableBeanFactory。DefaultListableBeanFactory實際包含了基本IOC容器所具有的所有重要功能,是一個完整的IOC容器。
ApplicationContext包含BeanFactory的所有功能,通常建議比BeanFactory優先。
BeanFactory體系結構是典型的工廠方法模式,即什麼樣的工廠生產什麼樣的產品。BeanFactory是最基本的抽象工廠,而其他的IOC容器只不過是具體的工廠,對應著各自的Bean定義方法。但同時,其他容器也針對具體場景不同,進行了擴充,提供具體的服務。 如下:
Resource resource = new FileSystemResource("beans.xml"); BeanFactory factory = new XmlBeanFactory(resource);
ClassPathResource resource = new ClassPathResource("beans.xml"); BeanFactory factory = new XmlBeanFactory(resource);
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"}); BeanFactory factory = (BeanFactory) context;
基本就是這些了,接著使用getBean(String beanName)方法就可以取得bean的例項;BeanFactory提供的方法及其簡單,僅提供了六種方法供客戶呼叫:
- boolean containsBean(String beanName) 判斷工廠中是否包含給定名稱的bean定義,若有則返回true
- Object getBean(String) 返回給定名稱註冊的bean例項。根據bean的配置情況,如果是singleton模式將返回一個共享例項,否則將返回一個新建的例項,如果沒有找到指定bean,該方法可能會丟擲異常
- Object getBean(String, Class) 返回以給定名稱註冊的bean例項,並轉換為給定class型別
- Class getType(String name) 返回給定名稱的bean的Class,如果沒有找到指定的bean例項,則排除NoSuchBeanDefinitionException異常
- boolean isSingleton(String) 判斷給定名稱的bean定義是否為單例模式
- String[] getAliases(String name) 返回給定bean名稱的所有別名
package org.springframework.beans.factory; import org.springframework.beans.BeansException; public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; Object getBean(String name) throws BeansException; <T> T getBean(String name, Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; boolean containsBean(String name); boolean isSingleton(String name) throws NoSuchBeanDefinitionException; boolean isPrototype(String name) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException; Class<?> getType(String name) throws NoSuchBeanDefinitionException; String[] getAliases(String name); }
FactoryBean
一般情況下,Spring通過反射機制利用<bean>的class屬性指定實現類例項化Bean,在某些情況下,例項化Bean過程比較複雜,如果按照傳統的方式,則需要在<bean>中提供大量的配置資訊。配置方式的靈活性是受限的,這時採用編碼的方式可能會得到一個簡單的方案。Spring為此提供了一個org.springframework.bean.factory.FactoryBean的工廠類介面,使用者可以通過實現該介面定製例項化Bean的邏輯。FactoryBean介面對於Spring框架來說佔用重要的地位,Spring自身就提供了70多個FactoryBean的實現。它們隱藏了例項化一些複雜Bean的細節,給上層應用帶來了便利。從Spring3.0開始,FactoryBean開始支援泛型,即介面宣告改為FactoryBean<T>的形式。
以Bean結尾,表示它是一個Bean,不同於普通Bean的是:它是實現了FactoryBean<T>介面的Bean,根據該Bean的ID從BeanFactory中獲取的實際上是FactoryBean的getObject()返回的物件,而不是FactoryBean本身,如果要獲取FactoryBean物件,請在id前面加一個&符號來獲取。後面我們會從原始碼來分析這一塊
package org.springframework.beans.factory; public interface FactoryBean<T> { T getObject() throws Exception; Class<?> getObjectType(); boolean isSingleton(); }
在該介面中還定義了以下3個方法:
- T getObject():返回由FactoryBean建立的Bean例項,如果isSingleton()返回true,則該例項會放到Spring容器中單例項快取池中;
- boolean isSingleton():返回由FactoryBean建立的Bean例項的作用域是singleton還是prototype;
- Class<T> getObjectType():返回FactoryBean建立的Bean型別。
當配置檔案中<bean>的class屬性配置的實現類是FactoryBean時,通過getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的物件,相當於FactoryBean#getObject()代理了getBean()方法。
例:如果使用傳統方式配置下面Car的<bean>時,Car的每個屬性分別對應一個<property>元素標籤。
public class Car { private int maxSpeed ; private String brand ; private double price ; //get//set 方法 }
如果用FactoryBean的方式實現就靈活點,下例通過逗號分割符的方式一次性的為Car的所有屬性指定配置值:
import org.springframework.beans.factory.FactoryBean; public class CarFactoryBean implements FactoryBean<Car> { private String carInfo ; public Car getObject() throws Exception { Car car = new Car(); String[] infos = carInfo.split(","); car.setBrand(infos[0]); car.setMaxSpeed(Integer.valueOf(infos[1])); car.setPrice(Double.valueOf(infos[2])); return car; } public Class<Car> getObjectType(){ return Car.class ; } public boolean isSingleton(){ return false ; } public String getCarInfo(){ return this.carInfo; } //接受逗號分割符設定屬性資訊 public void setCarInfo (String carInfo){ this.carInfo = carInfo; } }
有了這個CarFactoryBean後,就可以在配置檔案中使用下面這種自定義的配置方式配置CarBean了:
<bean d="car"class="com.chenhao.spring.CarFactoryBean" P:carInfo="大奔,600,1000000"/>
當呼叫getBean("car")時,Spring通過反射機制發現CarFactoryBean實現了FactoryBean的介面,這時Spring容器就呼叫介面方法CarFactoryBean#getObject()方法返回。如果希望獲取CarFactoryBean的例項,則需要在使用getBean(beanName)方法時在beanName前顯示的加上"&"字首:如getBean("&car");
獲取bean
接下來我們回到載入bean的階段,當我們顯示或者隱式地呼叫 getBean()
時,則會觸發載入 bean 階段。如下:
public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); }
內部呼叫 doGetBean()
方法,這個方法的程式碼比較長,各位耐心看下:
@SuppressWarnings("unchecked") protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { //獲取 beanName,這裡是一個轉換動作,將 name 轉換為 beanName final String beanName = transformedBeanName(name); Object bean; /* *檢查快取中的例項工程是否存在對應的例項 *為何要優先使用這段程式碼呢? *因為在建立單例bean的時候會存在依賴注入的情況,而在建立依賴的時候為了避免迴圈依賴 *spring建立bean的原則是在不等bean建立完就會將建立bean的objectFactory提前曝光,即將其加入到快取中,一旦下個bean建立時依賴上個bean則直接使用objectFactory *直接從快取中或singletonFactories中獲取objectFactory *就算沒有迴圈依賴,只是單純的依賴注入,如B依賴A,如果A已經初始化完成,B進行初始化時,需要遞迴呼叫getBean獲取A,這是A已經在快取裡了,直接可以從這裡取到 */ // Eagerly check singleton cache for manually registered singletons. 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 + "'"); } } //返回對應的例項,有些時候並不是直接返回例項,而是返回某些方法返回的例項 //這裡涉及到我們上面講的FactoryBean,如果此Bean是FactoryBean的實現類,如果name字首為"&",則直接返回此實現類的bean,如果沒有字首"&",則需要呼叫此實現類的getObject方法,返回getObject裡面真是的返回物件 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { //只有在單例的情況下才會解決迴圈依賴 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } //嘗試從parentBeanFactory中查詢bean BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } } //如果不是僅僅做型別檢查,則這裡需要建立bean,並做記錄 if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { //將儲存XML配置檔案的GenericBeanDefinition轉換為RootBeanDefinition,同時如果存在父bean的話則合併父bean的相關屬性 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); //如果存在依賴則需要遞迴例項化依賴的bean String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } registerDependentBean(dep, beanName); try { getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // 單例模式 // 例項化依賴的bean後對bean本身進行例項化 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); } // 原型模式 else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } // 從指定的 scope 下建立 bean else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // Check if required type matches the type of the actual bean instance. if (requiredType != null && !requiredType.isInstance(bean)) { try { T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return convertedBean; } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; }
程式碼是相當長,處理邏輯也是相當複雜,下面將其進行拆分講解。
獲取 beanName
final String beanName = transformedBeanName(name);
這裡傳遞的是 name,不一定就是 beanName,可能是 aliasName,也有可能是 FactoryBean(帶“&”字首),所以這裡需要呼叫 transformedBeanName()
方法對 name 進行一番轉換,主要如下:
protected String transformedBeanName(String name) { return canonicalName(BeanFactoryUtils.transformedBeanName(name)); } // 去除 FactoryBean 的修飾符 public static String transformedBeanName(String name) { Assert.notNull(name, "'name' must not be null"); String beanName = name; while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); } return beanName; } // 轉換 aliasName public String canonicalName(String name) { String canonicalName = name; // Handle aliasing... String resolvedName; do { resolvedName = this.aliasMap.get(canonicalName); if (resolvedName != null) { canonicalName = resolvedName; } } while (resolvedName != null); return canonicalName; }
主要處理過程包括兩步:
- 去除 FactoryBean 的修飾符。如果 name 以 “&” 為字首,那麼會去掉該 “&”,例如,
name = "&studentService"
,則會是name = "studentService"
。 - 取指定的 alias 所表示的最終 beanName。主要是一個迴圈獲取 beanName 的過程,例如別名 A 指向名稱為 B 的 bean 則返回 B,若 別名 A 指向別名 B,別名 B 指向名稱為 C 的 bean,則返回 C。
快取中獲取單例bean
單例在Spring的同一個容器內只會被建立一次,後續再獲取bean直接從單例快取中獲取,當然這裡也只是嘗試載入,首先嚐試從快取中載入,然後再次嘗試從singletonFactorry載入因為在建立單例bean的時候會存在依賴注入的情況,而在建立依賴的時候為了避免迴圈依賴,Spring建立bean的原則不等bean建立完成就會建立bean的ObjectFactory提早曝光加入到快取中,一旦下一個bean建立時需要依賴上個bean,則直接使用ObjectFactory;就算沒有迴圈依賴,只是單純的依賴注入,如B依賴A,如果A已經初始化完成,B進行初始化時,需要遞迴呼叫getBean獲取A,這是A已經在快取裡了,直接可以從這裡取到。接下來我們看下獲取單例bean的方法getSingleton(beanName),進入方法體:
@Override @Nullable public Object getSingleton(String beanName) { //引數true是允許早期依賴 return getSingleton(beanName, true); } @Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { //檢查快取中是否存在例項,這裡就是上面說的單純的依賴注入,如B依賴A,如果A已經初始化完成,B進行初始化時,需要遞迴呼叫getBean獲取A,這是A已經在快取裡了,直接可以從這裡取到 Object singletonObject = this.singletonObjects.get(beanName); //如果快取為空且單例bean正在建立中,則鎖定全域性變數,為什麼要判斷bean在建立中呢?這裡就是可以判斷是否迴圈依賴了。 //A依賴B,B也依賴A,A例項化的時候,發現依賴B,則遞迴去例項化B,B發現依賴A,則遞迴例項化A,此時會走到原點A的例項化,第一次A的例項化還沒完成,只不過把例項化的物件加入到快取中,但是狀態還是正在建立中,由此回到原點發現A正在建立中,由此可以判斷是迴圈依賴了 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { //如果此bean正在載入,則不處理 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { //當某些方法需要提前初始化的時候會直接呼叫addSingletonFactory把對應的ObjectFactory初始化策略儲存在singletonFactory中 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { //使用預先設定的getObject方法 singletonObject = singletonFactory.getObject(); 記錄在快取中,注意earlySingletonObjects和singletonFactories是互斥的 this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
接下來我們根據原始碼再來梳理下這個方法,這樣更易於理解,這個方法先嚐試從singletonObjects裡面獲取例項,如果如果獲取不到再從earlySingletonObjects裡面獲取,如果還獲取不到,再嘗試從singletonFactories裡面獲取beanName對應的ObjectFactory,然後再呼叫這個ObjectFactory的getObject方法建立bean,並放到earlySingletonObjects裡面去,並且從singletonFactoryes裡面remove調這個ObjectFactory,而對於後續所有的記憶體操作都只為了迴圈依賴檢測時候使用,即allowEarlyReference為true的時候才會使用。
這裡涉及到很多個儲存bean的不同map,簡單解釋下:
singletonObjects:用於儲存BeanName和建立bean例項之間的關係,beanName–>bean Instance
singletonFactories:用於儲存BeanName和建立bean的工廠之間的關係,banName–>ObjectFactory
earlySingletonObjects:也是儲存BeanName和建立bean例項之間的關係,與singletonObjects的不同之處在於,當一個單例bean被放到這裡面後,那麼當bean還在建立過程中,就可以通過getBean方法獲取到了,其目的是用來檢測迴圈引用。
registeredSingletons:用來儲存當前所有已註冊的bean.
從bean的例項中獲取物件
獲取到bean以後就要獲取例項物件了,這裡用到的是getObjectForBeanInstance方法。getObjectForBeanInstance是個頻繁使用的方法,無論是從快取中獲得bean還是根據不同的scope策略載入bean.總之,我們得到bean的例項後,要做的第一步就是呼叫這個方法來檢測一下正確性,其實就是檢測獲得Bean是不是FactoryBean型別的bean,如果是,那麼需要呼叫該bean對應的FactoryBean例項中的getObject()作為返回值。接下來我們看下此方法的原始碼:
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { //如果指定的name是工廠相關的(以&開頭的) if (BeanFactoryUtils.isFactoryDereference(name)) { //如果是NullBean則直接返回此bean if (beanInstance instanceof NullBean) { return beanInstance; } //如果不是FactoryBean型別,則驗證不通過丟擲異常 if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); } } // Now we have the bean instance, which may be a normal bean or a FactoryBean. // If it's a FactoryBean, we use it to create a bean instance, unless the // caller actually wants a reference to the factory. //如果獲取的beanInstance不是FactoryBean型別,則說明是普通的Bean,可直接返回 //如果獲取的beanInstance是FactoryBean型別,但是是以(以&開頭的),也直接返回,此時返回的是FactoryBean的例項 if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } Object object = null; if (mbd == null) { object = getCachedObjectForFactoryBean(beanName); } 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()); //到了這裡說明獲取的beanInstance是FactoryBean型別,但沒有以"&"開頭,此時就要返回factory內部getObject裡面的物件了 object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; }
接著我們來看看真正的核心功能getObjectFromFactoryBean(factory, beanName, !synthetic)方法中實現的,繼續跟進程式碼:
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { // 為單例模式且快取中存在 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) { // 若該 bean 處於建立中,則返回非處理物件,而不是儲存它 if (isSingletonCurrentlyInCreation(beanName)) { return object; } // 前置處理 beforeSingletonCreation(beanName); try { // 對從 FactoryBean 獲取的物件進行後處理 // 生成的物件將暴露給bean引用 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 例項物件中的核心方法之一了。這裡我們關注三個方法:beforeSingletonCreation()
、 afterSingletonCreation()
、 postProcessObjectFromFactoryBean()
。可能有小夥伴覺得前面兩個方法不是很重要,LZ 可以肯定告訴你,這兩方法是非常重要的操作,因為他們記錄著 bean 的載入狀態,是檢測當前 bean 是否處於建立中的關鍵之處,對解決 bean 迴圈依賴起著關鍵作用。before 方法用於標誌當前 bean 處於建立中,after 則是移除。其實在這篇部落格剛剛開始就已經提到了 isSingletonCurrentlyInCreation()
是用於檢測當前 bean 是否處於建立之中,如下:
public boolean isSingletonCurrentlyInCreation(String beanName) { return this.singletonsCurrentlyInCreation.contains(beanName); }
是根據 singletonsCurrentlyInCreation 集合中是否包含了 beanName,集合的元素則一定是在 beforeSingletonCreation()
中新增的,如下:
protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }
afterSingletonCreation()
為移除,則一定就是對 singletonsCurrentlyInCreation 集合 remove 了,如下:
protected void afterSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); } }
我們再來看看真正的核心方法 doGetObjectFromFactoryBean
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) throws BeanCreationException { Object object; try { if (System.getSecurityManager() != null) { AccessControlContext acc = getAccessControlContext(); try { object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { object = factory.getObject(); } } catch (FactoryBeanNotInitializedException ex) { throw new BeanCurrentlyInCreationException(beanName, ex.toString()); } catch (Throwable ex) { throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex); } // Do not accept a null value for a FactoryBean that's not fully // initialized yet: Many FactoryBeans just return null then. if (object == null) { if (isSingletonCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException( beanName, "FactoryBean which is currently in creation returned null from getObject"); } object = new NullBean(); } return object; }
以前我們曾經介紹過FactoryBean的呼叫方法,如果bean宣告為FactoryBean型別,則當提取bean時候提取的不是FactoryBean,而是FactoryBean中對應的getObject方法返回的bean,而doGetObjectFromFactroyBean真是實現這個功能。
而呼叫完doGetObjectFromFactoryBean方法後,並沒有直接返回,getObjectFromFactoryBean方法中還呼叫了object = postProcessObjectFromFactoryBean(object, beanName);方法,在子類AbstractAutowireCapableBeanFactory,有這個方法的實現:
@Override protected Object postProcessObjectFromFactoryBean(Object object, String beanName) { return applyBeanPostProcessorsAfterInitialization(object, beanName); } @Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { Object current = beanProcessor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
對於後處理器的使用,我們目前還沒接觸,後續會有大量篇幅介紹,這裡我們只需要瞭解在Spring獲取bean的規則中有這樣一條:儘可能保證所有bean初始化後都會呼叫註冊的BeanPostProcessor的postProcessAfterInitialization方法進行處理,在實際開發過程中大可以針對此特性設計自己的業務處理。