死磕Spring之IoC篇 - 開啟 Bean 的載入
阿新 • • 發佈:2021-03-01
> 該系列文章是本人在學習 Spring 的過程中總結下來的,裡面涉及到相關原始碼,可能對讀者不太友好,請結合我的原始碼註釋 [Spring 原始碼分析 GitHub 地址](https://github.com/liu844869663/spring-framework) 進行閱讀
>
> Spring 版本:5.1.14.RELEASE
>
> 開始閱讀這一系列文章之前,建議先檢視[**《深入瞭解 Spring IoC(面試題)》**](https://www.cnblogs.com/lifullmoon/p/14422101.html)這一篇文章
>
> 該系列其他文章請檢視:[**《死磕 Spring 之 IoC 篇 - 文章導讀》**](https://www.cnblogs.com/lifullmoon/p/14436372.html)
## 開啟 Bean 的載入
前面的一些列文章對**面向資源(XML、Properties)**、**面向註解**定義的 Bean 是如何被解析成 BeanDefinition(Bean 的“前身”),並儲存至 BeanDefinitionRegistry 註冊中心裡面,實際也是通過 ConcurrentHashMap 進行儲存。
Spring 底層 IoC 容器 DefaultListableBeanFactory,實現了 BeanFactory 和 BeanDefinitionRegistry 介面,這個時候它處於“就緒狀態”,當我們顯示或者隱式地呼叫 `getBean(...)` 方法時,會觸發載入 Bean 階段,獲取對應的 Bean。在該方法中,如果是單例模式會先從快取中獲取,已有則直接返回,沒有則根據 BeanDefinition 開始初始化這個 Bean。
### BeanFactory 體系結構
先來看看 BeanFactory 介面的繼承關係
簡單描述這些介面:
- `org.springframework.beans.factory.BeanFactory`,Spring IoC 容器最基礎的介面,提供依賴查詢**單個** Bean 的功能
- `org.springframework.beans.factory.ListableBeanFactory`,繼承 BeanFactory 介面,提供依賴查詢**多個** Bean 的功能
- `org.springframework.beans.factory.HierarchicalBeanFactory`,繼承 BeanFactory 介面,提供獲取父 BeanFactory 的功能,具有**層次性**
- `org.springframework.beans.factory.config.ConfigurableBeanFactory`,繼承 HierarchicalBeanFactory 介面,提供可操作內部相關元件的功能,具有**可配置性**
- `org.springframework.beans.factory.config.AutowireCapableBeanFactory`,繼承 BeanFactory 介面,提供可注入的功能,支援**依賴注入**
- `org.springframework.beans.factory.config.ConfigurableListableBeanFactory`,繼承上面所有介面,綜合所有特性,還提供可提前初始化所有單例 Bean 的功能
通過這些介面的名稱可以大致瞭解其用意,接下來我們來看看它們的實現類的繼承關係
簡單描述這些實現類:
- `org.springframework.beans.factory.support.AbstractBeanFactory` 抽象類,實現 ConfigurableBeanFactory 介面,基礎實現類,Bean 的建立過程交由子類實現
- `org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory` 抽象類,繼承 AbstractBeanFactory,實現 AutowireCapableBeanFactory 介面,完成 Bean 的建立
- `org.springframework.beans.factory.support.DefaultListableBeanFactory`,Spring 底層 IoC 容器,依賴注入的底層實現
其他的介面和類和 BeanDefinition 註冊中心,別名註冊中心,單例 Bean 註冊中心相關;右下角的 ApplicationContext 與 Spring 應用上下文有關,它的整個體系這裡不做展述,在後面的文章進行分析
### AbstractBeanFactory
`org.springframework.beans.factory.support.AbstractBeanFactory` 抽象類,實現 ConfigurableBeanFactory 介面,BeanFactory 的基礎實現類,提供依賴查詢方法,可獲取 Bean 物件,接下來我們來看看依賴查詢的實現
#### getBean 方法
`getBean(String name)` 方法,根據名稱獲取 Bean,當然還有許多過載方法,如下:
```java
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
@Override
public T getBean(String name, Class requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
public T getBean(String name, @Nullable Class requiredType, @Nullable Object... args)
throws BeansException {
return doGetBean(name, requiredType, args, false);
}
```
最終都會呼叫 `doGetBean(...)` 這個方法
> 當我們顯示或者隱式地呼叫這個方法時,會觸發 Bean 的載入;你是否會有疑問,我們使用 Spring 的過程中並不會呼叫這個方法去獲取 Bean,那這個方法會被誰呼叫呢?在 ConfigurableListableBeanFactory 介面中提供提前初始化所有單例 Bean 的功能,在 Spring 應用上下文(ApplicationContext)重新整理階段會提前初始化所有的單例 Bean,這個提前初始化也是呼叫 getBean 這個方法,這部分內容在後續分析 Spring 應用上下文的生命週期會講到
#### 【核心】doGetBean 方法
`doGetBean(final String name, @Nullable final Class requiredType, @Nullable final Object[] args, boolean typeCheckOnly)` 方法,獲取一個 Bean,方法如下:
```java
protected T doGetBean(final String name, @Nullable final Class requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// <1> 獲取 `beanName`
// 因為入參 `name` 可能是別名,也可能是 FactoryBean 型別 Bean 的名稱(`&` 開頭,需要去除)
// 所以需要獲取真實的 beanName
final String beanName = transformedBeanName(name);
Object bean;
// <2> 先從快取(僅快取單例 Bean )中獲取 Bean 物件,這裡快取指的是 `3` 個 Map
// 快取中也可能是正在初始化的 Bean,可以避免**迴圈依賴注入**引起的問題
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
// <3> 若從快取中獲取到對應的 Bean,且 `args` 引數為空
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// <3.1> 獲取 Bean 的目標物件,`scopedInstance` 非 FactoryBean 型別直接返回
// 否則,呼叫 FactoryBean#getObject() 獲取目標物件
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// 快取中沒有對應的 Bean,則開啟 Bean 的載入
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// <4> 如果**非單例模式**下的 Bean 正在建立,這裡又開始建立,表明存在迴圈依賴,則直接丟擲異常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
// <5> 如果從當前容器中沒有找到對應的 BeanDefinition,則從父容器中載入(如果存在父容器)
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// <5.1> 獲取 `beanName`,因為可能是別名,則進行處理
// 和第 `1` 步不同,不需要對 `&` 進行處理,因為進入父容器重新依賴查詢
String nameToLookup = originalBeanName(name);
// <5.2> 若為 AbstractBeanFactory 型別,委託父容器的 doGetBean 方法進行處理
// 否則,就是非 Spring IoC 容器,根據引數呼叫相應的 `getBean(...)`方法
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
// <6> 如果不是僅僅做型別檢查,則表示需要建立 Bean,將 `beanName` 標記為已建立過
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// <7> 從容器中獲取 `beanName` 對應的的 RootBeanDefinition(合併後)
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 檢查是否為抽象類
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// <8> 獲取當前正在建立的 Bean 所依賴物件集合(`depends-on` 配置的依賴)
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// <8.1> 檢測是否存在迴圈依賴,存在則丟擲異常
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// <8.2> 將 `beanName` 與 `dep` 之間依賴的關係進行快取
registerDependentBean(dep, beanName);
try {
// <8.3> 先建立好依賴的 Bean(重新呼叫 `getBean(...)` 方法)
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
// <9> 開始建立 Bean,不同模式建立方式不同
if (mbd.isSingleton()) { // <9.1> 單例模式
/*
* <9.1.1> 建立 Bean,成功建立則進行快取,並移除快取的早期物件
* 建立過程實際呼叫的下面這個 `createBean(...)` 方法
*/
sharedInstance = getSingleton(beanName,
// ObjectFactory 實現類
() -> {
try {
// **【核心】** 建立 Bean
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.
// 如果建立過程出現異常,則顯式地從快取中刪除當前 Bean 相關資訊
// 在單例模式下為了解決迴圈依賴,建立過程會快取早期物件,這裡需要進行刪除
destroySingleton(beanName);
throw ex;
}
});
// <9.1.2> 獲取 Bean 的目標物件,`scopedInstance` 非 FactoryBean 型別直接返回
// 否則,呼叫 FactoryBean#getObject() 獲取目標物件
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// <9.2> 原型模式
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
// <9.2.1> 將 `beanName` 標記為原型模式正在建立
beforePrototypeCreation(beanName);
// <9.2.2> **【核心】** 建立 Bean
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// <9.2.3> 將 `beanName` 標記為不在建立中,照應第 `9.2.1` 步
afterPrototypeCreation(beanName);
}
// <9.2.4> 獲取 Bean 的目標物件,`scopedInstance` 非 FactoryBean 型別直接返回
// 否則,呼叫 FactoryBean#getObject() 獲取目標物件
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// <9.3> 其他模式
else {
// <9.3.1> 獲取該模式的 Scope 物件 `scope`,不存在則丟擲異常
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 {
// <9.3.1> 從 `scope` 中獲取 `beanName` 對應的物件(看你的具體實現),不存在則執行**原型模式**的四個步驟進行建立
Object scopedInstance = scope.get(beanName, () -> {
// 將 `beanName` 標記為原型模式正在建立
beforePrototypeCreation(beanName);
try {
// **【核心】** 建立 Bean
return createBean(beanName, mbd, args);
}
finally {
// 將 `beanName` 標記為不在建立中,照應上一步
afterPrototypeCreation(beanName);
}
});
// 獲取 Bean 的目標物件,`scopedInstance` 非 FactoryBean 型別直接返回
// 否則,呼叫 FactoryBean#getObject() 獲取目標物件
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.
// <10> 如果入參 `requiredType` 不為空,並且 Bean 不是該型別,則需要進行型別轉換
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
// <10.1> 通過型別轉換機制,將 Bean 轉換成 `requiredType` 型別
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
// <10.2> 轉換後的 Bean 為空則丟擲異常
if (convertedBean == null) {
// 轉換失敗,丟擲 BeanNotOfRequiredTypeException 異常
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
// <10.3> 返回型別轉換後的 Bean 物件
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
// <11> 返回獲取到的 Bean
return (T) bean;
}
```
這個方法的處理過程有點長,如下:
1. 獲取 `beanName`,因為入參 `name` 可能是別名,也可能是 FactoryBean 型別 Bean 的名稱(`&` 開頭,需要去除),所以需要獲取真實的 `beanName`
2. 先從快取(僅快取單例 Bean )中獲取 Bean 物件,這裡快取指的是 `3` 個 Map;快取中也可能是正在初始化的 Bean,可以避免**迴圈依賴注入**引起的問題
3. 若從快取中獲取到對應的 Bean,且 `args` 引數為空
1. **【同】**呼叫 `getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd)` 方法
獲取 Bean 的目標物件,`scopedInstance` 非 FactoryBean 型別直接返回,否則,呼叫 FactoryBean#getObject() 獲取目標物件
------
快取中沒有對應的 Bean,則開啟 Bean 的載入
4. 如果**非單例模式**下的 Bean 正在建立,這裡又開始建立,表明存在迴圈依賴,則直接丟擲異常
5. 如果從當前容器中沒有找到對應的 BeanDefinition,則從**父容器**中載入(如果存在父容器)
1. 獲取 `beanName`,因為可能是別名,則進行處理,和第 `1` 步不同,不需要對 `&` 進行處理,因為進入父容器重新依賴查詢
2. 若為 AbstractBeanFactory 型別,委託父容器的 doGetBean 方法進行處理;否則,就是非 Spring IoC 容器,根據引數呼叫相應的 `getBean(...)`方法
6. 如果不是僅僅做型別檢查,則表示需要建立 Bean,將 `beanName` 標記為已建立過,在後面的**迴圈依賴檢查**中會使用到
7. 從容器中獲取 `beanName` 對應的的 RootBeanDefinition(合併後),呼叫 `getMergedLocalBeanDefinition(String beanName)` 方法
8. 獲取當前正在建立的 Bean 所依賴物件集合(`depends-on` 配置的依賴)
1. 檢測是否存在迴圈依賴,存在則丟擲異常
2. 將 `beanName` 與 `dep` 之間依賴的關係進行快取
3. 先建立好依賴的 Bean(重新呼叫 `getBean(...)` 方法)
------
9. 開始建立 Bean,不同模式建立方式不同
1. **單例模式**
1. 建立 Bean,成功建立則進行快取,並移除快取的早期物件,呼叫 `getSingleton(String beanName, ObjectFactory> singletonFactory)` 方法
**【核心】**入參的 ObjectFactory 實現類就是呼叫的 `AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])` 方法
2. **【同】** 和上面的 `3.1` 相同操作
2. **原型模式**
1. 將 `beanName` 標記為**非單例模式**正在建立
2. **【核心】** 建立 Bean,呼叫 `AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])` 方法
3. 將 `beanName` 標記為不在建立中,照應第 `9.2.1` 步
4. **【同】** 和上面的 `3.1` 相同操作
3. **其他模式**
1. 獲取該模式的 Scope 物件 `scope`,不存在則丟擲異常
2. 從 `scope` 中獲取 `beanName` 對應的物件(看你的具體實現),不存在則執行**原型模式**的四個步驟進行建立
------
10. 如果入參 `requiredType` 不為空,並且 Bean 不是該型別,則需要進行型別轉換
1. 通過型別轉換機制,將 Bean 轉換成 `requiredType` 型別
2. 轉換後的 Bean 為空則丟擲異常
3. 返回型別轉換後的 Bean 物件
11. 返回獲取到的 Bean
------
概括:
- 可以看到這個方法載入 Bean 的過程中,會先從快取中獲取**單例模式**的 Bean;
- 不管是從快取中獲取的還是新建立的,都會進行處理,如果是 FactoryBean 型別則呼叫其 getObject() 獲取目標物件;
- BeanFactory 可能有父容器,如果當前容器找不到 BeanDefinition 則會嘗試讓父容器建立;
- 建立 Bean 的任務交由 AbstractAutowireCapableBeanFactory 去完成;
- 如果獲取到的 Bean 不是我們想要型別,會通過型別轉換機制轉換成目標型別
接下來依次分析上述過程的相關步驟(`doGetBean(...)`)
### 1. 獲取 beanName
對應程式碼段:
```java
// AbstractBeanFactory.java
final String beanName = transformedBeanName(name);
```
因為入參 `name` 可能是別名,也可能是 FactoryBean 型別 Bean 的名稱(`&` 開頭,需要去除),所以需要進行一番轉換,如下:
```java
// AbstractBeanFactory.java
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
// BeanFactoryUtils.java
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
// 獲取 name 對應的 beanName,
// 不為 null 則返回 `transformedBeanNameCache` 快取中對應的 beanName,
// 為 null 則對 name 進行處理,將字首 '&' 去除,直至沒有 '&',然後放入 `transformedBeanNameCache` 快取中,並返回處理後的 beanName
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
// SimpleAliasRegistry.java
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
// 迴圈,從 aliasMap 中,獲取到最終的 beanName
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
```
過程並不複雜,先將字首 `&` 去除(如果存在),如果是別名則獲取對應的 `beanName`
> 定義了一個 FactoryBean 型別的 Bean,名稱為 `user`,通過 `user` 獲取 Bean,獲取到的是 FactoryBean#getObject() 返回的物件(只會被呼叫一次)
>
> 通過 `&user` 獲取 Bean,獲取到的是 FactoryBean 本身這個物件
### 2. 從快取中獲取單例 Bean
對應程式碼段:
```java
// AbstractBeanFactory#doGetBean(...) 方法
Object sharedInstance = getSingleton(beanName);
```
**單例模式**的 Bean 被建立後會快取,為了避免**迴圈依賴注入**,在建立過程會臨時快取正在建立的 Bean(早期 Bean),在後續文章會講到,從快取中獲取物件過程如下:
```java
// DefaultSingletonBeanRegistry.java
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// <1> **【一級 Map】**從單例快取 `singletonObjects` 中獲取 beanName 對應的 Bean
Object singletonObject = this.singletonObjects.get(beanName);
// <2> 如果**一級 Map**中不存在,且當前 beanName 正在建立
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// <2.1> 對 `singletonObjects` 加鎖
synchronized (this.singletonObjects) {
// <2.2> **【二級 Map】**從 `earlySingletonObjects` 集合中獲取,裡面會儲存從 **三級 Map** 獲取到的正在初始化的 Bean
singletonObject = this.earlySingletonObjects.get(beanName);
// <2.3> 如果**二級 Map** 中不存在,且允許提前建立
if (singletonObject == null && allowEarlyReference) {
// <2.3.1> **【三級 Map】**從 `singletonFactories` 中獲取對應的 ObjectFactory 實現類
ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);
// 如果從**三級 Map** 中存在對應的物件,則進行下面的處理
if (singletonFactory != null) {
// <2.3.2> 呼叫 ObjectFactory#getOject() 方法,獲取目標 Bean 物件(早期半成品)
singletonObject = singletonFactory.getObject();
// <2.3.3> 將目標物件放入**二級 Map**
this.earlySingletonObjects.put(beanName, singletonObject);
// <2.3.4> 從**三級 Map**移除 `beanName`
this.singletonFactories.remove(beanName);
}
}
}
}
// <3> 返回從快取中獲取的物件
return singletonObject;
}
```
過程如下:
1. **【一級 Map】**從單例快取 `singletonObjects` 中獲取 beanName 對應的 Bean
2. 如果**一級 Map**中不存在,且當前 beanName 正在建立
1. 對 `singletonObjects` 加鎖
2. **【二級 Map】**從 `earlySingletonObjects` 集合中獲取,裡面會儲存從 **三級 Map** 獲取到的正在初始化的 Bean
3. 如果**二級 Map** 中不存在,且允許提前建立
1. **【三級 Map】**從 `singletonFactories` 中獲取對應的 ObjectFactory 實現類,如果從**三級 Map** 中存在對應的物件,則進行下面的處理
2. 呼叫 ObjectFactory#getOject() 方法,獲取目標 Bean 物件(早期半成品)
3. 將目標物件放入**二級 Map**
4. 從**三級 Map**移除 beanName
3. 返回從快取中獲取的物件
這個過程對應[**《深入瞭解 Spring IoC(面試題)》**](https://www.cnblogs.com/lifullmoon/p/14422101.html)中的**BeanFactory 是如何處理迴圈依賴**問題
### 3. FactoryBean 的處理
> 一般情況下,Spring 通過反射機制利用 Bean 的 beanClass 屬性指定實現類來例項化 Bean。某些情況下,Bean 的例項化過程比較複雜,如果按照傳統的方式,則需要提供大量的配置資訊,配置方式的靈活性有限,這時採用編碼的方式可能會得到一個簡單的方案。Spring 為此提供了一個 FactoryBean 的工廠 Bean 介面,使用者可以通過實現該介面定製例項化 Bean 的邏輯。
>
> FactoryBean 介面對於 Spring 框架本身也非常重要,其內部就提供了大量 FactoryBean 的實現。它們隱藏了例項化過程中一些複雜細節,給上層應用帶來了便利。
對應程式碼段:
```java
// AbstractBeanFactory#doGetBean(...) 方法
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
```
不管是從快取中獲取的還是新建立的,都會呼叫這個方法進行處理,如果是 FactoryBean 型別則呼叫其 getObject() 獲取目標物件
#### getObjectForBeanInstance 方法
```java
// AbstractBeanFactory.java
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName,
@Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
// <1> 若 `name` 以 `&` 開頭,說明想要獲取 FactoryBean,則校驗其**正確性**
if (BeanFactoryUtils.isFactoryDereference(name)) {
// <1.1> 如果是 NullBean 空物件,則直接返回
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// <1.2> 如果不是 FactoryBean 型別,則丟擲異常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, 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.
// 到這裡我們就有了一個 Bean,可能是一個正常的 Bean,也可能是一個 FactoryBean
// 如果是 FactoryBean,則需要通過其 getObject() 方法獲取目標物件
// <2> 如果 `beanInstance` 不是 FactoryBean 型別,不需要再處理則直接返回
// 或者(表示是 FactoryBean 型別) `name` 以 `&` 開頭,表示你想要獲取實際 FactoryBean 物件,則直接返回
// 還不符合條件的話,表示是 FactoryBean,需要獲取 getObject() 返回目標物件
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
// <3> 如果入參沒有傳 BeanDefinition,則從 `factoryBeanObjectCache` 快取中獲取對應的 Bean 物件
// 入參傳了 BeanDefinition 表示這個 Bean 是剛建立的,不走快取,需要呼叫其 getObject() 方法獲取目標物件
// `factoryBeanObjectCache`:FactoryBean#getObject() 呼叫一次後返回的目標物件快取在這裡
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
// <4> 若第 `3` 步獲取的物件為空,則需要呼叫 FactoryBean#getObject() 獲得物件
if (object == null) {
// Return bean instance from factory.
// <4.1> 將 `beanInstance` 轉換成 FactoryBean 型別
FactoryBean> factory = (FactoryBean>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
// <4.2> 如果入參沒有傳 BeanDefinition 並且當前容器存在對應的 BeanDefinition
if (mbd == null && containsBeanDefinition(beanName)) {
// 獲取對應的 RootBeanDefinition(合併後)
mbd = getMergedLocalBeanDefinition(beanName);
}
// 是否是使用者定義的(不是 Spring 建立解析出來的)
boolean synthetic = (mbd != null && mbd.isSynthetic());
// <4.3> **【核心】**通過 FactoryBean 獲得目標物件,單例模式會快取在 `factoryBeanObjectCache` 中
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
```
過程如下:
1. 若 `name` 以 `&` 開頭,說明想要獲取 FactoryBean,則校驗其**正確性**
1. 如果是 NullBean 空物件,則直接返回
2. 如果不是 FactoryBean 型別,則丟擲異常
2. 如果 `beanInstance` 不是 FactoryBean 型別,不需要再處理則**直接返回**;或者(表示是 FactoryBean 型別) `name` 以 `&` 開頭,表示你想要獲取實際 FactoryBean 物件,則**直接返回**;還不符合條件的話,表示是 FactoryBean,需要獲取 getObject() 返回目標物件,**往下處理**
3. 如果入參沒有傳 BeanDefinition,則從 `factoryBeanObjectCache` 快取中獲取對應的 Bean 物件,如下:
```java
// FactoryBeanRegistrySupport.java
protected Object getCachedObjectForFactoryBean(String beanName) {
return this.factoryBeanObjectCache.get(beanName);
}
```
`factoryBeanObjectCache`:FactoryBean#getObject() 呼叫一次後返回的目標物件快取在這裡
入參傳了 BeanDefinition 表示這個 Bean 是剛建立的,不走快取,需要呼叫其 getObject() 方法獲取目標物件
4. 若第 `3` 步獲取的物件為空,則需要呼叫 FactoryBean#getObject() 獲得物件
1. 將 `beanInstance` 轉換成 FactoryBean 型別
2. 如果入參沒有傳 BeanDefinition 並且當前容器存在對應的 BeanDefinition,則獲取對應的 RootBeanDefinition(合併後)
3. **【核心】**通過 FactoryBean 獲得目標物件,單例模式會快取在 `factoryBeanObjectCache` 中,呼叫 `getObjectFromFactoryBean(FactoryBean>, String, boolean)` 方法
#### getObjectFromFactoryBean 方法
`getObjectFromFactoryBean(FactoryBean> factory, String beanName, boolean shouldPostProcess)` 方法,獲取 FactoryBean 的目標物件,方法如下:
```java
// FactoryBeanRegistrySupport.java
protected Object getObjectFromFactoryBean(FactoryBean> factory, String beanName, boolean shouldPostProcess) {
// <1> `factory` 為單例模式,且單例 Bean 快取中存在 `beanName` 對應的 FactoryBean 物件
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) { // <1.1> 獲取單例鎖,保證安全
// <1.2> 從 `factoryBeanObjectCache` 快取中獲取 FactoryBean#getObject() 建立的目標物件
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// <1.3> 則根據 `factory` 獲取目標物件,呼叫 FactoryBean#getObject() 方法
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
// <1.4> 這裡再進行一次校驗,看是否在快取中存在 FactoryBean 建立的目標物件,如果有則優先從快取中獲取
// 保證 FactoryBean#getObject() 只能被呼叫一次
// 沒有的話,則對剛獲取到的目標物件進行接下來的處理
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
} else {
// <1.5> 是否需要後續處理,這個 FactoryBean 的前身 BeanDefinition 是否由 Spring 解析出來的,通常情況下都是
if (shouldPostProcess) {
// <1.5.1> 若該 FactoryBean 處於建立中,則直接返回這個目標物件,不進行接下來的處理過程
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
// <1.5.2> 前置處理,將 `beanName` 標誌為正在建立
beforeSingletonCreation(beanName);
try {
// <1.5.3> 對通過 FactoryBean 獲取的目標物件進行後置處理
// 遍歷所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的處理)
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
// <1.5.4> 後置處理,將 `beanName` 標誌為不在建立中
afterSingletonCreation(beanName);
}
}
// <1.6> 如果快取中存在 `beanName` 對應的 FactoryBean 物件
// 上面不是判斷了嗎?也可能在上面的處理過程會有所變化,所以這裡在做一層判斷
// 目的:快取 FactoryBean 建立的目標物件,則需要保證 FactoryBean 本身這個物件存在快取中
if (containsSingleton(beanName)) {
// <1.6.1> 將這個 FactoryBean 建立的目標物件儲存至 `factoryBeanObjectCache`
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
// <1.7> 返回 FactoryBean 建立的目標物件
return object;
}
}
// <2> `factory` 非單例模式,或單例 Bean 快取中不存在 `beanName` 對應的 FactoryBean 物件
else {
// <2.1> 則根據 `factory` 獲取目標物件,呼叫 FactoryBean#getObject() 方法
Object object = doGetObjectFromFactoryBean(factory, beanName);
// <2.2> 是否需要後續處理,這個 FactoryBean 的前身 BeanDefinition 是否由 Spring 解析出來的,通常情況下都是
if (shouldPostProcess) {
try {
// <2.2.1> 對通過 FactoryBean 獲取的目標物件進行後置處理
// 遍歷所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的處理)
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
// <2.3> 返回 FactoryBean 建立的目標物件,非單例模式不會進行快取
return object;
}
}
```
過程如下:
1. `factory` 為單例模式,且單例 Bean 快取中存在 `beanName` 對應的 FactoryBean 物件
1. 獲取單例鎖,保證安全
2. 從 `factoryBeanObjectCache` 快取中獲取 FactoryBean#getObject() 建立的目標物件
3. 則根據 `factory` 獲取目標物件,呼叫 FactoryBean#getObject() 方法(反射機制)
4. 這裡再進行一次校驗(第 `1.2` 已經判斷過),看是否在快取中存在 FactoryBean 建立的目標物件,如果有則優先從快取中獲取,保證 FactoryBean#getObject() 只能被呼叫一次;沒有的話,則對剛獲取到的目標物件進行接下來的處理
5. 是否需要後續處理,這個 FactoryBean 的 BeanDefinition 是否由 Spring 解析出來的,通常情況下都是
1. 若該 FactoryBean 處於建立中,則直接返回這個目標物件,不進行接下來的處理過程
2. 前置處理,將 `beanName` 標誌為正在建立
3. 對通過 FactoryBean 獲取的目標物件進行後置處理,遍歷所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的處理)
4. 後置處理,將 `beanName` 標誌為不在建立中
5. 如果快取中存在 `beanName` 對應的 FactoryBean 物件,上面不是判斷了嗎(第 `1` 步判斷過)?
也可能在上面的處理過程會有所變化,所以這裡在做一層判斷,目的:快取 FactoryBean 建立的目標物件,則需要保證 FactoryBean 本身這個物件存在快取中
1. 將這個 FactoryBean 建立的目標物件儲存至 `factoryBeanObjectCache`
6. 返回 FactoryBean 建立的目標物件
2. `factory` 非單例模式,或單例 Bean 快取中不存在 `beanName` 對應的 FactoryBean 物件
1. 則根據 `factory` 獲取目標物件,呼叫 FactoryBean#getObject() 方法(反射機制)
2. 是否需要後續處理,這個 FactoryBean 的 BeanDefinition 是否由 Spring 解析出來的,通常情況下都是
1. 對通過 FactoryBean 獲取的目標物件進行後置處理,遍歷所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的處理)
3. 返回 FactoryBean 建立的目標物件,非單例模式不會進行快取
**概括**:呼叫 FactoryBean#getObject() 獲取目標物件,單例模式會快取起來;過程中 Sping 考慮到各種情況,例如保證單例模式下 FactoryBean#getObject() 只調用一次,是否需要進行後置處理。
### 4. 非單例模式依賴檢查
對應程式碼段:
```java
// AbstractBeanFactory#doGetBean(...) 方法
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null && (curVal.equals(beanName) // 相等
|| (curVal instanceof Set && ((Set>) curVal).contains(beanName)))); // 包含
}
```
`prototypesCurrentlyInCreation` 中儲存非單例模式下正在建立的 Bean 的名稱,這裡又重新建立,表示出現迴圈依賴,則直接丟擲異常
Spring 對於非單例模式的 Bean 無法進行相關快取,也就無法處理迴圈依賴的情況,選擇了直接丟擲異常
### 5. BeanFactory 層次性載入 Bean 策略
對應程式碼段:
```java
// AbstractBeanFactory#doGetBean(...) 方法
BeanFactory parentBeanFactory = getParentBeanFactory();
// <5> 如果從當前容器中沒有找到對應的 BeanDefinition,則從父容器中載入(如果存在父容器)
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// <5.1> 獲取 `beanName`,因為可能是別名,則進行處理
// 和第 `1` 步不同,不需要對 `&` 進行處理,因為進入父容器重新依賴查詢
String nameToLookup = originalBeanName(name);
// <5.2> 若為 AbstractBeanFactory 型別,委託父容器的 doGetBean 方法進行處理
// 否則,就是非 Spring IoC 容器,根據引數呼叫相應的 `getBean(...)`方法
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
```
如果**當前** BeanFactory 沒有對應的 BeanDefinition,也就無法建立 Bean,但是如果存在**父** BeanFactory,則將接下來的操作交由**父** BeanFactory,找不到會層層找上去,如果所有 BeanFactory 都找不到對應的 BeanDefinition 最終會丟擲異常。
### 6. 將 beanName 標記為已建立
對應程式碼段:
```java
// AbstractBeanFactory#doGetBean(...) 方法
// <6> 如果不是僅僅做型別檢查,則表示需要建立 Bean,將 `beanName` 標記為已建立過
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
```
如果不是僅僅做型別檢查,則呼叫 `markBeanAsCreated(String beanName)` 方法,如下:
```java
// AbstractBeanFactory.java
protected void markBeanAsCreated(String beanName) {
// 沒有建立
if (!this.alreadyCreated.contains(beanName)) {
// 加上全域性鎖
synchronized (this.mergedBeanDefinitions) {
// 再次檢查一次:DCL 雙檢查模式
if (!this.alreadyCreated.contains(beanName)) {
// Let the bean definition get re-merged now that we're actually creating
// the bean... just in case some of its metadata changed in the meantime.
// 從 mergedBeanDefinitions 中刪除 beanName,並在下次訪問時重新建立它
clearMergedBeanDefinition(beanName);
// 新增到已建立 bean 集合中
this.alreadyCreated.add(beanName);
}
}
}
}
```
將這個 `beanName` 儲存在 `alreadyCreated` 集合中(SetFromMap),在後面的**迴圈依賴檢查**中會使用到
### 7. 獲取 RootBeanDefinition
對應程式碼段:
```java
// AbstractBeanFactory#doGetBean(...) 方法
// <7> 從容器中獲取 `beanName` 對應的的 RootBeanDefinition(合併後)
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 檢查是否為抽象類
checkMergedBeanDefinition(mbd, beanName, args);
```
因為我們定義的 Bean 大多數都被 Spring 解析成 GenericBeanDefinition 型別,具有父子關係,則需要獲取最終的 BeanDefinition;如果存在父子關係,則會進行一系列的合併,轉換成 RootBeanDefinition 物件,呼叫 `getMergedLocalBeanDefinition(String beanName)` 方法,如下:
```java
// AbstractBeanFactory.java
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
// 從 `mergedBeanDefinitions` 快取中獲取合併後的 RootBeanDefinition,存在則直接返回
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null) {
return mbd;
}
// 獲取 BeanDefinition 並轉換成,如果存在父子關係則進行合併
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
throws BeanDefinitionStoreException {
return getMergedBeanDefinition(beanName, bd, null);
}
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
// 加鎖
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
// Check with full lock now in order to enforce the same merged instance.
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null) {
// 如果沒有父類則直接轉換成 RootBeanDefinition 物件
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
// 有父類則進行合併
else {
// Child bean definition: needs to be merged with parent.
BeanDefinition pbd;
try {
// 獲取父類的對應的 BeanDefinition 物件
String parentBeanName = transformedBeanName(bd.getParentName());
if (!beanName.equals(parentBeanName)) {
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without an AbstractBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// Deep copy with overridden values.
mbd = new RootBeanDefinition(pbd);
// 父子合併
mbd.overrideFrom(bd);
}
// Set default singleton scope, if not configured before.
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
}
// A bean contained in a non-singleton bean cannot be a singleton itself.
// Let's correct this on the fly here, since this might be the result of
// parent-child merging for the outer bean, in which case the original inner bean
// definition will not have inherited the merged outer bean's singleton status.
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// Cache the merged bean definition for the time being
// (it might still get re-merged later on in order to pick up metadata changes)
if (containingBd == null && isCacheBeanMetadata()) {
// 放入快取中
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
return mbd;
}
}
```
過程大致如下:
1. 從 `mergedBeanDefinitions` 快取中獲取合併後的 RootBeanDefinition,存在則直接返回,不存在則進行後面的操作
2. 獲取合併後的 RootBeanDefinition 物件,邏輯並不複雜,將一些屬性進行合併;這裡對於**父** BeanDefinition 的獲取也存在層次性查詢策略;注意,如果一個單例 BeanDefinition 包含在非單例 BeanDefinition,那麼會變成非單例 Bean
後續還會對合並後的 RootBeanDefinition 物件進行檢查,如果是抽象的,則丟擲異常
### 8. 依賴 Bean 的處理
對應程式碼段:
```java
// AbstractBeanFactory#doGetBean(...) 方法
// Guarantee initialization of beans that the current bean depends on.
// <8> 獲取當前正在建立的 Bean 所依賴物件集合(`depends-on` 配置的依賴)
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// <8.1> 檢測是否存在迴圈依賴,存在則丟擲異常
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// <8.2> 將 `beanName` 與 `dep` 之間依賴的關係進行快取
registerDependentBean(dep, beanName);
try {
// <8.3> 先建立好依賴的 Bean(重新呼叫 `getBean(...)` 方法)
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
```
- 每個 Bean 不一定是單獨工作的,可以通過 `depends-on` 配置依賴的 Bean,其他 Bean 也可以依賴它
- 對於依賴的 Bean,會優先載入,所以在 Spring 的載入順序中,在初始化某個 Bean 的時候,首先會初始化這個 Bean 的依賴
#### isDependent 方法
在初始化依賴的 Bean 之前,會呼叫 `isDependent(String beanName, String dependentBeanName)` 方法,判斷是否出現迴圈依賴,方法如下:
```java
DefaultSingletonBeanRegistry.java
protected boolean isDependent(String beanName, String dependentBeanName) {
synchronized (this.dependentBeanMap) {
return isDependent(beanName, dependentBeanName, null);
}
}
private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set alreadySeen) {
// <1> `alreadySeen` 中已經檢測過該 `beanName` 則直接返回 `false`
if (alreadySeen != null && alreadySeen.contains(beanName)) {
return false;
}
// <2> 獲取最終的 `beanName`,因為可能是別名,需要進行相關處理
String canonicalName = canonicalName(beanName);
// <3> 從 `dependentBeanMap` 中獲取依賴 `beanName` 的 Bean 集合
Set dependentBeans = this.dependentBeanMap.get(canonicalName);
// <4> 沒有 Bean 依賴該 `beanName`,也就不存在迴圈依賴,返回 `false`
if (dependentBeans == null) {
return false;
}
// <5> 依賴 `beanName` 的 Bean 們包含 `dependentBeanName`,表示出現迴圈依賴,返回 `true`
if (dependentBeans.contains(dependentBeanName)) {
// `beanName` 與 `dependentBeanName` 相互依賴
return true;
}
// <6> 對依賴該 `beanName` 的 Bean 們進行檢查,看它們是否與 `dependentBeanName` 存在依賴,遞迴處理
for (String transitiveDependency : dependentBeans) {
if (alreadySeen == null) {
alreadySeen = new HashSet<>();
}
alreadySeen.add(beanName);
if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
return true;
}
}
return false;
}
```
過程大致如下:
1. `alreadySeen` 中已經檢測過該 `beanName` 則直接返回 `false`
2. 獲取最終的 `beanName`,因為可能是別名,需要進行相關處理
3. 從 `dependentBeanMap` 中獲取依賴 `beanName` 的 Bean 集合
4. 沒有 Bean 依賴該 `beanName`,也就不存在迴圈依賴,返回 `false`
5. 依賴 `beanName` 的 Bean 們包含 `dependentBeanName`,表示出現迴圈依賴,返回 `true`
6. 對依賴該 `beanName` 的 Bean 們進行檢查,看它們是否與 `dependentBeanName` 存在依賴,遞迴處理
判斷是否出現迴圈依賴的過程有點繞,需要花點時間理解一下。例如:現在檢查 A ->(依賴)B,看是否出現迴圈依賴,我獲取到依賴 A 的所有 Bean,看 B 是否依賴這裡面的 Bean,如果出現 A -> B -> C -> A,那就出現迴圈依賴了。如果出現**迴圈依賴**,則會**丟擲異常**,所以我們說 Spring 處理了單例 Bean 的**迴圈依賴注入**比較好一點。
#### registerDependentBean 方法
將 `beanName` 與 `dep`(`beanName` 的依賴)之間依賴的關係進行快取,呼叫 `registerDependentBean(String beanName, String dependentBeanName)` 方法,如下:
```java
DefaultSingletonBeanRegistry.java
public void registerDependentBean(String beanName, String dependentBeanName) {
String canonicalName = canonicalName(beanName);
// 對應關係:beanName -> 依賴 beanName 的集合
synchronized (this.dependentBeanMap) {
Set dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName,
k -> new LinkedHashSet<>(8));
if (!dependentBeans.add(dependentBeanName)) {
return;
}
}
// 對應關係:beanName - > beanName 的依賴的集合
synchronized (this.dependenciesForBeanMap) {
Set dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName,
k -> new LinkedHashSet<>(8));
dependenciesForBean.add(canonicalName);
}
}
```
將兩者的依賴關係儲存起來,目的是在 `isDependent` 方法中判斷是否出現迴圈依賴
#### getBean 方法
載入 `beanName` 依賴的 Bean,同樣是呼叫 `AbstractBeanFactory#getBean(String dep)` 方法,也就是本文開頭講的這個方法
### 9. 不同作用域的 Bean 的建立
Spring 的作用域劃分為三種:單例模式、原型模式、其他模式,會依次進行判斷,然後進行建立,建立過程都是一樣的,主要是儲存範圍不一樣
- 單例模式:一個 BeanFactory 有且僅有一個例項
- 原型模式:每次依賴查詢和依賴注入生成新 Bean 物件
- 其他模式,例如 `request` 作用域會將 Bean 儲存在 ServletRequest 上下文中;`session` 作用域會將 Bean 儲存在 HttpSession 中;`application` 作用域會將 Bean 儲存在 ServletContext 中
#### 單例模式
對應程式碼段:
```java
// AbstractBeanFactory#doGetBean(...) 方法
if (mbd.isSingleton()) { // <9.1> 單例模式
/*
* <9.1.1> 建立 Bean,成功建立則進行快取,並移除快取的早期物件
* 建立過程實際呼叫的下面這個 `createBean(...)` 方法
*/
sharedInstance = getSingleton(beanName,
// ObjectFactory 實現類
() -> {
try {
// **【核心】** 建立 Bean
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.
// 如果建立過程出現異常,則顯式地從快取中刪除當前 Bean 相關資訊
// 在單例模式下為了解決迴圈依賴,建立過程會快取早期物件,這裡需要進行刪除
destroySingleton(beanName);
throw ex;
}
});
// <9.1.2> 獲取 Bean 的目標物件,`scopedInstance` 非 FactoryBean 型別直接返回
// 否則,呼叫 FactoryBean#getObject() 獲取目標物件
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
```
如果是單例模式,建立過程大致如下:
1. 呼叫 `DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory> singletonFactory)` 方法
建立 Bean,成功建立則進行快取,並移除快取的早期物件,建立過程實際呼叫的下面這個 `AbstractAutowireCapableBeanFactory#createBean(...)` 方法
2. FactoryBean 的處理,在前面 **3. FactoryBean 的處理** 中已經分析過
##### getSingleton 方法
`DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory> singletonFactory)` 方法,單例模式下獲取單例 Bean,如下:
```java
// DefaultSingletonBeanRegistry.java
public Object getSingleton(String beanName, ObjectFactory> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
// 全域性加鎖
synchronized (this.singletonObjects) {
// <1> 從 `singletonObjects` 單例 Bean 的快取中獲取 Bean(再檢查一遍),存在則直接返回,否則開始建立
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// <2> 將 `beanName` 標記為單例模式正在建立
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
/**
* <3> 建立 Bean,實際呼叫
* {@link AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])} 方法
*/
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// <4> 將 `beanName` 標記為不在建立中,照應第 `2` 步
afterSingletonCreation(beanName);
}
// <5> 如果這裡是新建立的單例模式 Bean,則在 `singletonObjects` 中進行快取(無序),移除快取的早期物件
// 並在 `registeredSingletons` 中儲存 `beanName`,保證註冊順序
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
```
過程大致如下:
1. 從 `singletonObjects` 單例 Bean 的快取中獲取 Bean(再檢查一遍),存在則直接返回,否則開始建立
2. 將 `beanName` 標記為單例模式正在建立
3. **【核心】**建立 Bean,實際呼叫 `AbstractAutowireCapableBeanFactory#createBean(...)` 方法
4. 將 `beanName` 標記為不在建立中,照應第 `2` 步
5. 如果這裡是新建立的單例模式 Bean,則在 `singletonObjects` 中進行快取(無序),移除快取的早期物件,並在 `registeredSingletons` 中儲存 `beanName`,保證註冊順序
##### createBean 方法
`AbstractAutowireCapableBeanFactory#createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)` 方法,建立 Bean,整個過程大致如下:
1. Bean 的例項化
2. 屬性賦值(包括依賴注入)
3. Aware 介面回撥
4. 呼叫初始化方法
上面涉及到 Bean 生命週期的大部分階段,將會在後續的文章中依次分析
#### 原型模式
對應程式碼段:
```java
// AbstractBeanFactory.java
// <9.2> 原型模式
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
// <9.2.1> 將 `beanName` 標記為**非單例模式**正在建立
beforePrototypeCreation(beanName);
// <9.2.2> **【核心】** 建立 Bean
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// <9.2.3> 將 `beanName` 標記為不在建立中,照應第 `9.2.1` 步
afterPrototypeCreation(beanName);
}
// <9.2.4> 獲取 Bean 的目標物件,`scopedInstance` 非 FactoryBean 型別直接返回
// 否則,呼叫 FactoryBean#getObject() 獲取目標物件
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
```
過程大致如下:
1. 將 `beanName` 標記為**非單例模式**正在建立
2. **【核心】**建立 Bean 也是呼叫 `AbstractAutowireCapableBeanFactory#createBean(...)` 方法,這裡沒有快取,每次載入 Bean 都會建立一個物件
3. 將 `beanName` 標記為不在建立中,照應第 `1` 步
4. FactoryBean 的處理,在前面 **3. FactoryBean 的處理** 中已經分析過
#### 其他模式
對應程式碼段:
```java
// AbstractBeanFactory.java
// <9.3> 其他模式
else {
// <9.3.1> 獲取該模式的 Scope 物件 `scope`,不存在則丟擲異常
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 {
// <9.3.2> 從 `scope` 中獲取 `beanName` 對應的物件(看你的具體實現),不存在則執行**原型模式**的四個步驟進行建立
Object scopedInstance = scope.get(beanName, () -> {
// 將 `beanName` 標記為**非單例模式**式正在建立
beforePrototypeCreation(beanName);
try {
// **【核心】** 建立 Bean
return createBean(beanName, mbd, args);
}
finally {
// 將 `beanName` 標記為不在建立中,照應上一步
afterPrototypeCreation(beanName);
}
});
// 獲取 Bean 的目標物件,`scopedInstance` 非 FactoryBean 型別直接返回
// 否則,呼叫 FactoryBean#getObject() 獲取目標物件
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);
}
}
```
過程如下:
1. 獲取該模式的 Scope 物件 `scope`,不存在則丟擲異常
2. 從 `scope` 中獲取 `beanName` 對應的物件(看你的具體實現),不存在則執行**原型模式**的四個步驟進行建立
想要自定義一個作用域,可以實現 `org.springframework.beans.factory.config.Scope` 介面,並往 Spring 應用上下文註冊即可
### 10. 型別轉換
對應程式碼段:
```java
// AbstractBeanFactory#doGetBean(...) 方法
// <10> 如果入參 `requiredType` 不為空,並且 Bean 不是該型別,則需要進行型別轉換
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
// <10.1> 通過型別轉換機制,將 Bean 轉換成 `requiredType` 型別
T convertedBean = getTypeConvert