Spring Ioc源碼分析系列--Bean實例化過程(一) 前言 上一篇文章Spring Ioc源碼分析系列--Ioc容器註冊BeanPostProcessor後置處理器以及事件消息處理已經完成了對IoC容器啟動方法也就是refresh()方法的簡單分析。但是之前的分析在對容器實例化Bean的過程 ...
Spring Ioc源碼分析系列--Bean實例化過程(一)
前言
上一篇文章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
開始,話不多說,開始分析吧。
源碼分析
bean實例化入口
還記得實例化入口的方法名嗎?回憶一下,算了,反正也不會有人記得。是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();
}
}
}
}
獲取BeanDefinition
首先跟進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
里,功能和屬性名區分度還是十分貼切的