前言
計劃趕不上變化,原本年前準備將這個主題告一段落,但各種工作之外的事接踵而至,且剩下的工作量依然超過我的預期,只能拖到現在,前段時間接了商業化廣告的活,源碼看得多了自己寫時總不自覺的按更高的標準要求自己,一遍遍的修改重構,這可能就是所謂的潛移默化吧
bean
加載三部曲中的第一部按照doGetBean(String, Class<T>, Object[], boolean)
自上而下的代碼結構將加載分為if-else
兩段,前段在getBean
顯式調用時返回單例對象以及自定義FactoryBean
生成bean
時調用,其中的重點為部分解決循環依賴的“三層緩存”和getObjectForBeanInstance(Object, String, String, RootBeanDefinition)
,后段由初始化過程中隱式調用以及獲得多例對象時調用,在第二部中介紹了隱式調用的整個流程,最后剩下createBean(String, RootBeanDefinition, Object[])
核心創建bean
尚未分析,本篇文章就與這部分內容相關
由于只剩下createBean
這個核心方法了,那么我們還是像前面將核心方法分成幾塊講解
標注1生成最終能實例化的
Class
類型,但并沒有根據Class
實例化出對象在分析解析XML并將解析后內容封裝成
GenericBeanDefinition
過程中曾今說過<bean>
中class
屬性與GenericBeanDefinition
父類AbstractBeanDefinition
中Object beanClass
對應,這里mbd.hasBeanClass()
就是判斷beanClass
是否instanceof Class
,如果是直接返回,因為我們要的就是Class
類型,不是的話最終調用doResolveBeanClass(RootBeanDefinition, Class<?>)
,該方法依然是個中轉方法,主要根據傳入的typesToMatch
生成特定的ClassLoader
,之后還要調用RootBeanDefinition#resolveBeanClass
,根據特定的加載器或者默認加載器加載出class
屬性對應的Class
對象,其生成Class
的動作又委派給工具類ClassUtils
我們將創建
Class
流程分成三部分:第一部分主要處理一些“原始”數據類型,舉個簡單的例子我在XML中配置如下
<bean id="myInt" class="java.lang.Integer">
我定義的對象就是“原始”數據類型,這種類型的Class處理就由第一部分負責,具體是怎么做的呢,實際上是兩個Map
,一個是resolvePrimitiveClassName(String)
中隱含的primitiveTypeNameMap
,另一個就是commonClassCache
,對應的代碼給大家看一下
在
ClassUtils
加載時就會將基本數據類型,基本數據類型對應的包裝類型,基本數據類型數組和包裝類型數組等Class
放入兩個Map
中,如果我們配置的類屬于其中的一個直接返回對應的Class
即可。圖3紅框2內代碼處理的類型為java.lang.String[]
、[Ljava.lang.String;
和[[Ljava.lang.String;
,第一個我可以嘗試模擬出來,后兩個實在沒搞明白怎么模擬,有知道的讀者麻煩告知。如果之前根據typesToMatch
生成了特定的類加載器就用這個ClassLoader
加載Class
,否則使用默認加載器,默認類加載是首先使用當前線程類加載器,如果還是沒有獲取到使用當前類的類加載器。這一系列的操作后RootBeanDefinition
中的beanClass
屬性除了異常情況就都是對應<bean>
生成對象的Class
了回到圖1標注2代碼是對
<lookup-method>
和<replaced-method>
兩種method injection
方式的預處理,在Spring解析之IoC:<bean>解析及Bean的注冊中我們沒有詳細闡述兩個標簽的解析存儲過程,在這里大致了解一下,兩個標簽解析后分別封裝在LookupOverride
和ReplaceOverride
中,兩個對象都繼承自抽象父類MethodOverride
,而多個該類對象又存放在AbstractBeanDefinition
成員變量MethodOverrides methodOverrides
中,下面我已<lookup-method>
舉個例子,說明下此類標簽的用法已經解決的問題<lookup-method>
標簽最重要的一個用途就是在單例對象內注入一個多例對象,我們知道構造器注入和setter
注入是兩種最常用的注入方式,但如果說到實現單例對象中注入多例對象需求,這兩種注入方式都鞭長莫及,因為在Spring創建出單例對象時相關的依賴注入流程都已經完成,也就是說依賴的對象只能注入一次,為了解決這個問題,Spring提出了method injection
方法注入,我們先來例子讓大家有個直觀的認識。首先定義一個單例對象SingletonService
該類是一個抽象類,存在返回多例對象的抽象方法,再定義一個多例對象的抽象接口
Prototype
有接口了必然有就有一個或多個實現,這里為了簡便只提供了一個實現類
在XML中進行
<bean>
配置實現類
scope = prototype
否則就失去了動態注入的意義了,lookup-method
中name
獲得多例對象的抽象方法名稱,bean
為返回bean
的類型,比如這里就是任何實現了Prototype
接口的實現類id/name
,如果讀者想跟深入了解的話,我給出一篇文章Method Injection。說了一堆做鋪墊再來看圖1標注2做了什么上面說過所有的方法注入標簽都存放在
methodOverrides
,遍歷所有的MethodOverride
,根據<lookup-method>
或<replaced-method>
中抽象方法名(name
屬性的值)和抽象類中所有同名的抽象方法比較,算出符合name
的抽象方法數量,為什么要這樣呢?我試驗了一下,結果是可能存在同名重載方法,最簡單的例子就是同名抽象方法但參數不同,但<lookup-method>
或<replaced-method>
中有無法配置抽象方法的參數,所以需要全部計數。那為什么但只存在一個符合抽象方式時setOverloaded(false)
呢?其實讀者可以將這里的判斷和下面的使用分為兩部分考慮,如果存在多個重載方法,那么使用時必定要再次判斷到底配置的是哪一個,如果只有一個符合要求這里加上一個標識,在下面使用的時候就省去了再次判斷的開銷圖1的標注3主要的目的在注釋上寫的還是比較清楚的,給用戶一個機會可以返回目標對象的代理實例,如果返回不為
null
,即返回了代理對象就直接返回,在正式說這部分邏輯之前還得先補充一個知識,在前面說過Spring提供后處理器接口BeanPostProcessor
,提供了在初始化對象后修改實例的能力,該接口有很多子接口,后面有機會會一一介紹,現在先說一種InstantiationAwareBeanPostProcessor
,除了父類提供的兩個待實現接口外又提供了另外三種,分別為Object postProcessBeforeInstantiation(Class<?>, String)
、boolean postProcessAfterInstantiation(Object, String)
和PropertyValues postProcessPropertyValues(PropertyValues, PropertyDescriptor[], Object, String)
,為了更好的說明還是舉個例子InstantiationAwareBeanPostProcessorImpl
實現了接口所有的方法,并做了一些打印以便觀看現象,在XML中也加上簡單的配置
<bean id="student" class="com.xiaomi.bean.Student">
<property name="name" value="zhangsan"></property>
</bean>
<bean id="instantiationAwareBeanPostProcessor" class="com.xiaomi.bean.InstantiationAwareBeanPostProcessorImpl"></bean>
運行并兩次獲得Student
實例打印,結果如下
很明顯在生成
Student
實例前調用了postProcessBeforeInstantiation
,那么我們可以在這個時候對目標對象進行一定的包裝或者處理,達到類似AOP的目的,之后真正創建了Student
實例,創建完成進行屬性的注入,在注入之前會調用postProcessPropertyValues
,在該方法中我們將原本注入的zhangsan
替換成了lisi
,“調包”后Spring調用了setter
進行屬性注入,最后才調用父接口BeanPostProcessor
的兩個方法,這個順序之前已經說過,沒什么意外的。我們獲得了兩次Student
對象由打印語句發現實現InstantiationAwareBeanPostProcessor
只會在創建對象前調用一次,當然,如果這里Student
是多例,自然就會被第二次處理。講到這里我們將postProcessBeforeInstantiation
注釋去除,在運行一遍看看結果有什么不同我們發現只剩下
postProcessBeforeInstantiation
和postProcessAfterInitialization
兩個方法的調用(Student
構造器也是在postProcessBeforeInstantiation
中顯式調用的,而不是Spring容器創建對象時默認調用),為什么會出現這種情況,其實我們回到源碼看一下處理邏輯就都清楚了上圖代碼對應圖1的標注3,在初始化時Spring會檢測是否存在自定義類實現了
InstantiationAwareBeanPostProcessor
接口,如果存在會將DefaultListableBeanFactory
中成員變量hasInstantiationAwareBeanPostProcessors
置為true
,這里的boolean hasInstantiationAwareBeanPostProcessors()
判斷通過調用第一個下劃線方法邏輯很簡單,首先獲得所有后處理器,判斷其中所有實現
InstantiationAwareBeanPostProcessor
的類,進而調用它的postProcessBeforeInstantiation
,最后將我們自己實現方法的返回值返回。resolveBeforeInstantiation
根據是否返回對象(代理)判斷是否調用applyBeanPostProcessorsAfterInitialization(RootBeanDefinition, String)
方法中調用了
BeanPostProcessor
的postProcessAfterInitialization(Object, String)
,再看看圖1的總流程,如果bean != null
就直接返回,聯想上面的例子bean != null
實際上就是我們生成代理的情況,那就是說如果有代理直接返回代理對象,且只會調用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
和BeanPostProcessor#postProcessAfterInitialization
,所表現出來的結果正是例子圖12的樣子,既然調了包返回了代理那就沒有必要再創建原始的目標類了,否則進入圖1標注4創建目標類實例的代碼,代碼清單2
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// (1)
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// (2)
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
// (3)
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// (4)
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");
}
// (5)
addSingletonFactory(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// (6)
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// (7)
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
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);
}
}
// (8)
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
// (9)
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
Spring首先創建了一個bean
的包裝類,按照官方文檔上的說法提供該類的好處有:1.提供了設置單個和成塊屬性值的功能,可以獲得屬性的descriptors
,查詢屬性是否可讀可寫;2.支持屬性的無限嵌套;2.具有不改變目標類代碼情況下,添加PropertyChangeListeners
和VetoableChangeListeners
功能等。還想深入了解該類的讀者可以看Bean manipulation and the BeanWrapper。如果緩存中已經存在我們后續要操作的BeanWrapper
,直接移除取出做后續處理如標注1,如果暫時不存在該對象標注2處代碼進行創建,此處是getBean
核心邏輯之一,Spring根據創建對象方式的不同又在該方法內部分為三部分:1.根據factory-method工廠方法進行創建;2.匹配一個或多個參數的有參構造器創建;3.默認無參進行實例化。后續會用專門的文章對這三種方式的創建流程進行分析。
到目前為止我們已經遇過兩個后處理器相關的接口,一個是BeanPostProcessor
,另一個是它的子接口InstantiationAwareBeanPostProcessor
,標注3又會引出一個BeanPostProcessor
的子接口MergedBeanDefinitionPostProcessor
,除了父接口的兩個方法外還需實現該接口的類給出postProcessMergedBeanDefinition(RootBeanDefinition, Class<?>, String)
,前面我們說過如果<bean>
存在父子關系,Spring在解析之后會將父子關系的<bean>
映射成為RootBeanDefinition
,那么該后處理器及待實現方法就是在做RootBeanDefinition
的后處理工作
標注4根據:1.是否單例;2.是否允許循環引用標志;3.beanName
對應的bean
是否正在創建中三個條件決定是否允許“早期單例暴露”。同樣的,我們說過Spring中部分解決循環依賴的第三級緩存正是標注5的代碼,如果判斷允許“早期單例暴露”就將創建該單例對象的ObjectFactory
存入三級緩存singletonFactories
。當要獲得單例對象時Spring會調用自定義ObjectFactory
的getObject()
,其實就是這里的getEarlyBeanReference(String, RootBeanDefinition, Object)
這里又出現一個新的后處理器
SmartInstantiationAwareBeanPostProcessor
,它繼承自InstantiationAwareBeanPostProcessor
,新提供了三個待實現方法:1.Class<?> predictBeanType(Class, String)
用于預測返回bean
的Class
類型,一般在隱式初始化時調用;2.Constructor<?>[] determineCandidateConstructors(Class<?>, String)
存在多個構造器時用于決定使用哪個進行類的初始化,在上面說過的通過有參構造器創建對象時調用;3.Object getEarlyBeanReference(Object, String)
用于獲得早期暴露的單例對象引用,和MergedBeanDefinitionPostProcessor
類似,一般不需要我們人為擴展,而是Spring內部自己使用。標注6主要是對BeanWrapper
進行屬性的填充,代碼清單3
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
// (1)
if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
// (2)
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
// (3)
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
// (4)
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
// (5)
applyPropertyValues(beanName, mbd, bw, pvs);
}
Spring初始化解析XML配置文件時,所有的<property>
會放入PropertyValue
的集合中,集合又被封裝入MutablePropertyValues
對象中。標注1的判斷邏輯是,如果不存在是<bean>
對應實體BeanWrapper
但還存在解析出的屬性,肯定出現問題了,拋出異常;如果不存在實體也不存在屬性,那也沒有繼續往下解析的必要了,直接返回。標注2又一次用到了上面講過的InstantiationAwareBeanPostProcessor
,如果存在實現該接口后處理器,則調用boolean postProcessAfterInstantiation(Object, String)
,進行對象實例創建后的處理,這里依然存在一個短路操作,如果方法返回false,continueWithPropertyPopulation
為假,如果該值非真,也無需進行后處理器對于屬性處理等后續操作了。標注3很明顯涉及按名稱、按類型兩種屬性注入方式,后續會有專門文章分析注入原理,這里不做闡述。標注4根據是否有InstantiationAwareBeanPostProcessor
或依賴檢查標識判斷是否進行屬性的“調包”處理,處理的過程就是InstantiationAwareBeanPostProcessor
自有方法的最后一個PropertyValues postProcessPropertyValues(PropertyValues, PropertyDescriptor[], Object, String)
。到這里Spring得到了所有需要填充的屬性(兩種方式注入的、后處理器調包的),最后調用標注5處代碼真正將屬性設置進BeanWrapper
對象中,代碼清單4
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs == null || pvs.isEmpty()) {
return;
}
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
if (System.getSecurityManager() != null) {
if (bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
}
// (1)
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
original = mpvs.getPropertyValueList();
}
else {
original = Arrays.asList(pvs.getPropertyValues());
}
// (2)
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// (3)
// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
// (4)
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
// (5)
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// (6)
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
// (7)
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
// (8)
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
// (9)
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
標注1首先判斷所有屬性整體是否都被轉換,如果是就不需要下面的步驟,直接賦值返回;如果并不是所有屬性已經轉換過,就會首先按標注2獲取用戶自定義的類型轉換器。標注3創建了新集合用于存放轉換后的結果,之后遍歷每一個屬性并依次判斷轉換與否,沒有轉換則標注4根據上面創建的解析器valueResolver
對該值進行解析,我們知道除了最普通的String外Spring支持多種形式的屬性配置,該方法中就包含了幾乎所有類型屬性的解析流程,這里給出一張表格涉及所有解析的類型已經該類型在讀取XML時對應的封裝類型
真實類型 | 封裝類型 |
---|---|
Array |
ManagedArray |
List |
ManagedList |
Set |
ManagedSet |
Map |
ManagedMap |
Bean |
BeanDefinitionHolder |
ref引用Bean |
RuntimeBeanReference |
idref |
RuntimeBeanNameReference |
Properties |
ManagedProperties |
String |
TypedStringValue |
SPEL表達式 |
TypedStringValue |
如果判斷該屬性是可轉換的convertible = true
,就會開始標注5的自定義轉換器的轉換,如果原始值originalValue
與經過Spring內置解析器解析后的值resolvedValue
相同,且可轉換標識convertible
為真說明必定經過了自定義轉換的步驟(不管是否真的轉換過),此時用最新的convertedValue
替換老值,如果標識6所示。實際上我覺得標注6和7具有相同的目的,只要convertible
為真就說明最新的值必然為convertedValue
,那也必然要更新屬性封裝對象對應字段了。標注8將屬性對象設為整體已轉化,與方法一開始根據此判斷直接返回還是開始轉換相呼應。標注9終于將解析后數組封裝入MutablePropertyValues
,再塞入BeanWrapper
中,至此創建對象中的屬性填充流程分析完畢
接著代碼清單2分析看標注7,“初始化”Bean
該方法嚴格意義上來說并不是做了
Bean
的初始化,因為此時參數的bean
已經是實例化完成的對象了,只不過該對象還在Spring內部,并沒有暴露給用戶,方法內主要做了三件事:1.感知類對象相關屬性的設置;2.后處理器方法的處理;3.init-method
屬性的處理。我們一個個來看,如果bean
實現了BeanNameAware
、BeanClassLoaderAware
和BeanFactoryAware
三種Aware
接口中的一個或多個,則調用對應的實現方法,雖然大家可能對這三者不太熟悉,另一個Aware
接口ApplicatonContextAware
相信大家都用過,該接口的setApplicationContext(ApplicationContext)
能讓我們得到Spring的上下文對象,ApplicatonContextAware
和這里的三個接口處理方式如出一轍,只是觸發時機不同,前者是在bean
后處理階段觸發,后者則是在這里的Spring容器生命周期初始階段紅線2又碰到
bean
后處理器了,后處理器有多種變體,上面提到過InstantiationAwareBeanPostProcessor
和SmartInstantiationAwareBeanPostProcessor
,并且在Spring解析之IoC:bean的加載(一)中也用例子的形式詳解了BeanPostProcessor
的用法,有了前面的基礎這里后處理器也就非常好理解了,標注2和4分別對應了BeanPostProcessor
的Object postProcessBeforeInitialization(Object, String)
和Object postProcessAfterInitialization(Object, String)
,方法內會遍歷所有實現BeanPostProcessor
接口的類調用每個類的上述兩個方法。同樣的在Spring解析之IoC:bean的加載(一)的BeanPostProcessor
例子中我們曾經說過后處理器的before/after
是相對于實現了InitializingBean
接口afterPropertiesSet()
方法的執行時刻來說的,那么看圖中標注3不是正處在前后方法中間嗎?我們有理由猜測invokeInitMethods(String, Object, RootBeanDefinition)
就是對于afterPropertiesSet()
的處理橫線代碼驗證了我們的猜測,但是我們發現除了調用
afterPropertiesSet()
外還有一處紅框內的邏輯沒有想到。之前說過Spring提供了三對在bean
初始化和銷毀時進行自定義操作的手段:1.@PostConstruct/@PreDestory
;2.<bean>
的init-method/destroy-method
屬性;3.實現InitializingBean/DisposableBean
接口,這段代碼就是針對第二種情況進行的處理,方法invokeCustomInitMethod(String, Object, RootBeanDefinition)
內部做了一些權限控制后得到配置init-method
的Method
對象,最終通過反射調用該方法初始化
bean
方法分析完畢,我們回到圖17從宏觀看看各個流程的步驟,其實這就是Spring容器中bean
生命周期那張圖的執行流程
Instantiate
對應代碼清單2標注2instanceWrapper = createBean(beanName, mbd, args);
第一次創建bean
Popluate properties
對應代碼清單3整個屬性填充過程BeanNameAware's setBeanName()
對應圖17invokeAwareMethods(String, Object)
處理第一個BeanNameAware
流程BeanFactoryAware's setBeanFactory()
對應圖17invokeAwareMethods(String, Object)
處理第三個BeanFactoryAware
流程Pre-initializatioin beanPostProcessors
對應圖17標注2代碼applyBeanPostProcessorsBeforeInitialization(Object, String)
InitializingBean's afterPropertiesSet()
對應圖18紅線處邏輯Call custom init-method
對應圖18紅框內代碼Post-initialization beanPostProcessors
對應圖17標注4代碼applyBeanPostProcessorsAfterInitialization(Object, String)
生命周期中的最后兩個狀態雖然現在沒有遇到,但大家看名字就很明顯9與6InitializingBean
接口對應,一個初始化一個銷毀;10destroy-method
屬性和7init-method
對應。記得剛學習Spring時,這個生命周期是永遠記不住的知識點,但整個源碼分析下來就清清爽爽了
回到主線代碼清單2,標注8處代碼看上去一大堆,實際這段被執行到的可能性很小,earlySingleton = true
會調用我們曾今說的Object getSingleton(String, boolean)
,我們將方法放在現在的“語境”中再分析一下
讀者需要知道的是,這段代碼在
new ClassPathXmlApplicationContext()
隱式調用和getBean
多例對象時才有可能調用,對于多例來說earlySingletonExposure = false
,意味著代碼不會執行;對于隱式調用allowEarlyReference = false
說明紅框處內的代碼不會執行,再結合代碼清單2標注5addSingletonFactory(String, ObjectFactory)
可以推得只存在singletonObjects
中已有beanName
對應對象這一種可能,整個邏輯代碼才會往下執行,介于此該流程就不繼續往下分析了。最后看下代碼清單2標注9該方法的主要作用是對實現
Disposable
接口的對象進行注冊,注意,這里只是注冊,因為銷毀必定是在容器關閉時調用的,而這里所有的一切都是對象初始化流程,所以只能是注冊,并且只有單例對象且實現Disposable
接口的destroy()
或者實現DestructionAwareBeanPostProcessor
接口的postProcessBeforeDestruction(Object, String)
才會真正注冊。注冊分為兩大塊,單例的和自定義scope
的。單例對象銷毀注冊調用registerDisposableBean(String, DisposableBean)
,將beanName-bean
映射放入Map<String, Object> disposableBeans
即結束;自定義scope
由于需要實現Scope
接口,其中就包含這里的registerDestructionCallback(String, Runnable)
。至此Spring獲取bean
邏輯基本講解完畢,階段性勝利,哈哈