上一篇文章Spring Ioc原始碼分析系列--Ioc容器註冊BeanPostProcessor後置處理器以及事件訊息處理已經完成了對IoC容器啟動方法也就是refresh()
方法的簡單分析。但是之前的分析在對容器範例化Bean的過程的略過了,留到了這後續的文章分析,所以這篇文章會對Bean的範例化過程做一個介紹。
首先來理一下本文的思路:關鍵詞是範例化。由於Spring是利用反射實現的範例化,腦子裡先簡單想一下Java裡利用發射範例化一個物件需要哪些步驟和操作。毫無疑問,我們首先要知道物件的class
,接著需要確定使用什麼建構函式以及確定建構函式的引數等。利用這些已經基本可以實現一個物件的範例化,當然實際上需要的東西可能更多更復雜,這裡只是舉個例子。那麼需要的這些資訊可以去哪裡提取呢?對Spring有了解的可能都馬上能想到BeanDefinition
,這是一份原料表,裡面有我們構造一個範例化物件所需的所有引數。如果不太理解這個定義,可以參考一下上篇文章的例子。
如果不清楚BeanDefinition是從哪裡來的以及不清楚如何定義的,可以參考之前的文章Spring Ioc原始碼分析系列--Ioc原始碼入口分析的關鍵實現系列方法 loadBeanDefinitions ()
。這篇文章講解註冊的時候只是說了註冊到容器裡,並沒有說明具體是註冊到了哪裡,這裡點明一下,所謂講BeanDefinition
註冊到容器裡,就是將BeanDefinition
放入到容器的一個Map裡,具體是註冊到了DefaultListableBeanFactory
的beanDefinitionMap
屬性裡,beanName
會儲存到beanDefinitionNames
屬性裡,這是個list
集合,裡面的beanName
會保持註冊時候的順序。
範例化的開始就是從遍歷所有的beanName
開始,話不多說,開始分析吧。
還記得範例化入口的方法名嗎?回憶一下,算了,反正也不會有人記得。是beanFactory.preInstantiateSingletons()
,具體實現是在DefaultListableBeanFactory
類裡。
跟程序式碼檢視,可以看到,這段程式碼分為兩部分,第一個for迴圈用於先範例化物件,第二個for迴圈完成一些範例化之後的回撥操作。我們先來看第一個for迴圈,首先是遍歷所有的beanNames
獲取BeanDefinition
,然後根據工廠bean
和非工廠bean
進行相應處理,最後呼叫getBean(beanName)
範例化物件。注意這裡範例化的是非抽象的、單例的並且是非懶載入的bean,這個前提非常重要。
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
// 所有bd的名稱
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
// 遍歷所有bd,一個個進行建立
for (String beanName : beanNames) {
// 獲取到指定名稱對應的bd
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 對不是延遲載入的單例的Bean進行建立
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 判斷是否是一個FactoryBean
if (isFactoryBean(beanName)) {
// 如果是一個factoryBean的話,先建立這個factoryBean,建立factoryBean時,需要在beanName前面拼接一個&符號
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
// 判斷是否是一個SmartFactoryBean,並且不是懶載入的,就意味著,在建立了這個factoryBean之後要立馬呼叫它的getObject方法建立另外一個Bean
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 不是factoryBean的話,我們直接建立就行了
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
// 在建立了所有的Bean之後,遍歷為所有適用的 bean 觸發初始化後回撥,也就是這裡會對延遲初始化的bean進行載入...
for (String beanName : beanNames) {
// 這一步其實是從快取中獲取對應的建立的Bean,這裡獲取到的必定是單例的
Object singletonInstance = getSingleton(beanName);
// 判斷是否是一個SmartInitializingSingleton,
// 最典型的就是我們之前分析過的EventListenerMethodProcessor,
// 在這一步完成了對已經建立好的Bean的解析,會判斷其方法上是否有 @EventListener註解,
// 會將這個註解標註的方法通過EventListenerFactory轉換成一個事件監聽器並新增到監聽器的集合中
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
首先跟進getMergedLocalBeanDefinition(beanName)
方法,這裡首先會嘗試從mergedBeanDefinitions
裡去獲取,這個mergedBeanDefinitions
存放著已經合併過的BeanDefinition
,獲取不到再真正呼叫getMergedBeanDefinition(beanName, getBeanDefinition(beanName))
去獲取。
/**
* Return a merged RootBeanDefinition, traversing the parent bean definition
* if the specified bean corresponds to a child bean definition.
*
* 返回一個合併的 RootBeanDefinition,如果指定的 bean 對應於子 bean 定義,則遍歷父 bean 定義。
*
* @param beanName the name of the bean to retrieve the merged definition for
* @return a (potentially merged) RootBeanDefinition for the given bean
* @throws NoSuchBeanDefinitionException if there is no bean with the given name
* @throws BeanDefinitionStoreException in case of an invalid bean definition
*/
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
// 首先檢查 mergedBeanDefinitions ,最小程度影響並行效能
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null && !mbd.stale) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
先看getBeanDefinition(beanName)
,這個方法就是簡單的去beanDefinitionMap
裡獲取BeanDefinition
,如果獲取不到,就丟擲異常。beanDefinitionMap
就是上面說到的BeanDefinition
存放的地方。
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
if (bd == null) {
if (logger.isTraceEnabled()) {
logger.trace("No bean named '" + beanName + "' found in " + this);
}
throw new NoSuchBeanDefinitionException(beanName);
}
return bd;
}
接下來就進入到getMergedBeanDefinition()
方法獲取BeanDefinition
,為啥要從beanDefinitionMap
獲取了還進行一個merged獲取呢?這是因為Bean有層次關係,子類需要合併父類別的屬性方法等,所以要進行一次合併,合併完成後會放入到mergedBeanDefinitions
裡,功能和屬性名區分度還是十分貼切的