[TOC]
<br/>
<br/>
> ## `BeanFactory` `getBean(name)`

> ### `BeanFactory`

* `BeanFactory`
```
public interface BeanFactory {
//這里是對FactoryBean的轉義定義,因為如果使用bean的名字檢索FactoryBean得到的對象是工廠生成的對象
String FACTORY_BEAN_PREFIX = "&";
//這里根據bean的名字,在IOC容器中得到bean實例,這個IOC容器就是一個大的抽象工廠。
Object getBean(String name) throws BeansException;
//這里根據bean的名字和Class類型來得到bean實例,和上面的方法不同在于它會拋出異常:如果根據名字取得的bean實例的Class類型和需要的不同的話。
<T> T getBean(String name, Class<T> requiredType);
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
//這里提供對bean的檢索,看看是否在IOC容器有這個名字的bean
boolean containsBean(String name);
//這里根據bean名字得到bean實例,并同時判斷這個bean是不是單件
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//這里根據bean名字得到bean實例,并同時判斷這個bean是不是原型
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
//這里對得到bean實例的Class類型
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
//這里得到bean的別名,如果根據別名檢索,那么其原名也會被檢索出來
String[] getAliases(String name);
}
```
* `HierarchicalBeanFactory`,是為了實現bean工廠的層級關系提供支持,其中聲明兩個方法
```
//得到父工廠
BeanFactory getParentBeanFactory();
//在本地工廠中有沒有給定名稱的bean,不包括繼承的工廠
boolean containsLocalBean(String name);
```
<br/>
> ### `getBean()`
```
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
// beanName轉換 1、移除&開頭的字符 2、處理alis別名
final String beanName = transformedBeanName(name);
Object bean;
//從bean的實例緩存中獲取,singletonObjects緩存,map結構 Map<beanName, beanInstance>
Object sharedInstance = getSingleton(beanName);
// sharedInstance = null,緩存里還沒有對應的實例,表明這個實例還沒創建。
// BeanFactory 并不會在一開始就將所有的單例 bean 實例化好,而是在調用 getBean 獲取時再實例化,懶加載
// ApplicatioContext會在spring啟動時先將所有的bean都加載好
// getBean 方法有很多重載,比如 getBean(String name, Object... args)
// BeanFactory 會根據這些參數 args 去匹配合適的構造方法構造 bean 實例。
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 + "'");
}
}
//如果 sharedInstance 是普通的單例 bean,下面的方法會直接返回
//如果sharedInstance 是 FactoryBean 類型的,則需調用 getObject 工廠方法獲取真正的bean 實例
//如果用戶想獲取 FactoryBean 本身,這里也不會做特別的處理,直接返回
//FactoryBean 的實現類本身也是一種 bean。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
/*
* 如果上面的條件不滿足,則表明 sharedInstance 可能為空,此時 beanName 對應的 bean
* 實例可能還未創建。這里還存在另一種可能,如果當前容器有父容器,beanName 對應的 bean 實例
* 可能是在父容器中被創建了,所以在創建實例前,需要先去父容器里檢查一下。
*/
else {
//如果上面的條件不滿足,則表明 sharedInstance 可能為空,此時 beanName 對應的 bean還未創建
//還存在另一種可能,如果當前容器有父容器,beanName 對應的 bean 實例
可能在父容器中創建了
//所以需要檢查一下父容器
// BeanFactory 不緩存 Prototype 類型的 bean,無法處理該類型 bean 的循環依賴問題
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 如果 sharedInstance = null,則到父容器中查找 bean 實例
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 獲取 name 對應的 beanName,如果 name 是以 & 字符開頭,則返回 & + beanName
String nameToLookup = originalBeanName(name);
// 根據 args 是否為空,以決定調用父容器哪個方法獲取 bean
if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// 合并父 BeanDefinition 與子 BeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 檢查是否有 dependsOn 依賴,如果有則先初始化所依賴的 bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
//檢測是否存在 depends-on 循環依賴
//depends-on 循環,Spring 會直接
拋出異常
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 注冊依賴記錄
registerDependentBean(dep, beanName);
try {
// 加載 depends-on 依賴
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// 創建 bean 實例
if (mbd.isSingleton()) {
/*
* 這里并沒有直接調用 createBean 方法創建 bean 實例,而是通過
* getSingleton(String, ObjectFactory) 方法獲取 bean 實例。
* getSingleton(String, ObjectFactory) 方法會在內部調用
* ObjectFactory 的 getObject() 方法創建 bean,并會在創建完成后,
* 將 bean 放入緩存中。關于 getSingleton 方法的分析,本文先不展開,我會在
* 后面的文章中進行分析
*/
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
// 創建 bean 實例
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
});
// 如果 bean 是 FactoryBean 類型,則調用工廠方法獲取真正的 bean 實例。否則直接返回 bean 實例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 創建 prototype 類型的 bean 實例
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 創建其他類型的 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, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
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;
}
}
// 如果需要進行類型轉換,則在此處進行轉換。類型轉換這一塊我沒細看,就不多說了。
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
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());
}
}
// 返回 bean
return (T) bean;
}
```
> ### `beanName`轉換
* 處理以字符 `&` 開頭的 `name`,處理別名。
```
protected String transformedBeanName(String name) {
// 這里調用了兩個方法:
// BeanFactoryUtils.transformedBeanName(name) 處理&字符
//canonicalName 轉換別名
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
```
<br/>
> ### 從緩存中獲取`bean`實例。
* 對于單例`bean`,`Spring`容器只會實例化一次。后續再次獲取時,只需直接從緩存里獲取即可,無需且不能再次實例化。
* 從緩存中取`bean`實例的方法是`getSingleton(String)`。
```
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
// allowEarlyReference表示是否允許其他 bean 引用正在創建中的 bean,用于處理循環引用的問題。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 從 singletonObjects 獲取實例,singletonObjects 中緩存的實例都是完全實例化好的 bean,可以直接使用
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 從 earlySingletonObjects 中獲取提前曝光的 bean,用于處理循環引用
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果如果 singletonObject = null,且允許提前曝光 bean 實例,則從相應的 ObjectFactory 獲取一個原始的(raw)bean(尚未填充屬性)
if (singletonObject == null && allowEarlyReference) {
// 獲取相應的工廠類,獲取對應beanName的工廠類
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 提前曝光 bean 實例,用于解決循環依賴
//此處為實際創建bean實例
singletonObject = singletonFactory.getObject();
// 放入上級緩存,如果還有其他 bean 依賴當前 bean,其他 bean 可以直接從 earlySingletonObjects 取結果
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
```
* 其中涉及了三個緩存

<br/>
> ### 合并父 BeanDefinition 與 子 BeanDefinition
* `Spring` 支持配置繼承,在標簽中可以使用`parent`屬性配置父類 `bean`。這樣子類 `bean` 可以繼承父類 `bean` 的配置信息,同時也可覆蓋父類中的配置。比如下面的配置:
```
<bean id="hello" class="xyz.coolblog.innerbean.Hello">
<property name="content" value="hello"/>
</bean>
<bean id="hello-child" parent="hello">
<property name="content" value="I`m hello-child"/>
</bean>
```
<br/>
> ### 從 `FactoryBean` 中獲取 `bean` 實例
* 單例類型,將`FactoryBean`生成的`bean`放入緩存
* 非單例,每次創建新的`bean`
***
> ### 參考
#### [Spring IOC 容器源碼分析 - 循環依賴的解決辦法](https://segmentfault.com/a/1190000015221968)
#### [Spring IOC 容器源碼分析 - 獲取單例 bean](http://www.tianxiaobo.com/2018/06/01/Spring-IOC-%E5%AE%B9%E5%99%A8%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-%E8%8E%B7%E5%8F%96%E5%8D%95%E4%BE%8B-bean/)
#### [Spring IOC 容器源碼分析系列文章](http://www.tianxiaobo.com/2018/05/30/Spring-IOC-%E5%AE%B9%E5%99%A8%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%E7%B3%BB%E5%88%97%E6%96%87%E7%AB%A0%E5%AF%BC%E8%AF%BB/)
- asD
- Java
- Java基礎
- Java編譯器
- 反射
- collection
- IO
- JDK
- HashMap
- ConcurrentHashMap
- LinkedHashMap
- TreeMap
- 阻塞隊列
- java語法
- String.format()
- JVM
- JVM內存、對象、類
- JVM GC
- JVM監控
- 多線程
- 基礎概念
- volatile
- synchronized
- wait_notify
- join
- lock
- ThreadLocal
- AQS
- 線程池
- Spring
- IOC
- 特性介紹
- getBean()
- creatBean()
- createBeanInstance()
- populateBean()
- AOP
- 基本概念
- Spring處理請求的過程
- 注解
- 微服務
- 服務注冊與發現
- etcd
- zk
- 大數據
- Java_spark
- 基礎知識
- Thrift
- hdfs
- 計算機網絡
- OSI七層模型
- HTTP
- SSL
- 數據庫
- Redis
- mysql
- mybatis
- sql
- 容器
- docker
- k8s
- nginx
- tomcat
- 數據結構/算法
- 排序算法
- 快排
- 插入排序
- 歸并排序
- 堆排序
- 計算時間復雜度
- leetcode
- LRU緩存
- B/B+ 樹
- 跳躍表
- 設計模式
- 單例模式
- 裝飾者模式
- 工廠模式
- 運維
- git
- 前端
- thymeleaf
- 其他
- 代碼規范
- work_project
- Interview