前言
上篇文章我們對(duì) BeanDefinition 進(jìn)行了討論,BeanDefinition 是對(duì) Bean 的定義,其保存了 Bean 的各種信息,如屬性、構(gòu)造方法參數(shù)、是否單例、是否延遲加載等。這里的注冊(cè) Bean 是指將 Bean 定義成 BeanDefinition,之后放入 Spring 容器中,我們常說的容器其實(shí)就是 Beanfactory 中的一個(gè) Map,key 是 Bean 的名稱,value 是 Bean 對(duì)應(yīng)的 BeanDefinition,這個(gè)注冊(cè) Bean 的方法由 BeanFactory 子類實(shí)現(xiàn)。
注:本篇文章使用的 SpringBoot 版本為 2.0.3.RELEASE,其 Spring 版本為 5.0.7.RELEASE
正文
在前面的《Spring(三)核心容器 - ApplicationContext 上下文啟動(dòng)準(zhǔn)備》文章中說過,當(dāng)前環(huán)境的 BeanFactory 實(shí)現(xiàn)類是 DefaultListableBeanFactory,是一個(gè)具有注冊(cè)功能的完整 Bean 工廠,注冊(cè) Bean 的方法是 registerBeanDefinition,DefaultListableBeanFactory 通過實(shí)現(xiàn) BeanDefinitionRegistry 接口,重寫該方法。
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
...
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
...
}
...
}
討論 registerBeanDefinition 方法之前,先來簡(jiǎn)單介紹 BeanDefinitionRegistry 接口。
1、BeanDefinitionRegistry 簡(jiǎn)介
BeanDefinitionRegistry 是一個(gè)接口,它定義了關(guān)于 BeanDefinition 的注冊(cè)、移除、查詢等一系列的操作。
public interface BeanDefinitionRegistry extends AliasRegistry {
// 注冊(cè) BeanDefinition
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;
// 移除 BeanDefinition
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 獲取 BeanDefinition
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 根據(jù) beanName 判斷容器是否存在對(duì)應(yīng)的 BeanDefinition
boolean containsBeanDefinition(String beanName);
// 獲取所有的 BeanDefinition
String[] getBeanDefinitionNames();
// 獲取 BeanDefinition 數(shù)量
int getBeanDefinitionCount();
// 判斷 beanName 是否被占用
boolean isBeanNameInUse(String beanName);
}
該接口有三個(gè)實(shí)現(xiàn)類:DefaultListableBeanFactory、GenericApplicationContext、SimpleBeanDefinitionRegistry,其中 GenericApplicationContext 底層調(diào)用的是 DefaultListableBeanFactory 中的實(shí)現(xiàn)方法,所以嚴(yán)格意義上來說,只有兩個(gè)實(shí)現(xiàn)類。這里,我們主要討論 DefaultListableBeanFactory 中的方法實(shí)現(xiàn)。
2、registerBeanDefinition 方法注冊(cè) Bean
前面說過 registerBeanDefinition 方法的主要實(shí)現(xiàn)類是 DefaultListableBeanFactory :
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
...
// 存儲(chǔ)所有的 BeanDefinition ,key 是 Bean 的名稱。我們一直稱呼的容器,底層就是這個(gè) Map
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
// 存儲(chǔ)所有 Bean 名稱
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
// 存儲(chǔ)手動(dòng)注冊(cè)的單例 Bean 名稱
private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);
// 存儲(chǔ)凍結(jié)的 BeanDefinition,留作后面緩存用
private volatile String[] frozenBeanDefinitionNames;
...
// 方法的入?yún)?Bean 名稱和對(duì)應(yīng)的 BeanDefinition
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
// 如果 beanDefinition 的實(shí)例為 AbstractBeanDefinition,則進(jìn)行驗(yàn)證
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
// 驗(yàn)證:
// 如果有重寫方法,但是是工廠方法,則拋出異常,因?yàn)橹貙懛椒ㄐ枰?,而工廠方法無法代理;
// 通過方法名稱,判斷 Bean 中該名稱方法存在的數(shù)量,0:方法不存在,報(bào)錯(cuò);1:方法非重載,overloaded 屬性設(shè)為 false;
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
// 先從 beanDefinitionMap 中嘗試獲取 beanName 對(duì)應(yīng) BeanDefinition
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
// 不為 null,則 beanName 對(duì)應(yīng)的 BeanDefinition 已經(jīng)存在
if (oldBeanDefinition != null) {
// 是否應(yīng)允許覆蓋 BeanDefinition,不允許則拋異常
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
/***************************** 若允許覆蓋 *****************************/
// 判斷 Bean 的角色大小:
// 0:用戶定義的 Bean、1:來源于配置文件的 Bean、2:Spring 內(nèi)部的 Bean;
// 當(dāng)原 BeanDefinition 角色小于新的 BeanDefinition 角色時(shí),輸出一個(gè) warn 日志,提示 BeanDefinition 被覆蓋
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
// 當(dāng)新 BeanDefinition 屬性值不等于原 BeanDefinition 屬性值時(shí),輸出 info 提示信息
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
// 最后,輸出 debug 日志信息:用等效的新 BeanDefinition 覆蓋原 BeanDefinition
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
// 添加至 BeanDefinition 集合,并覆蓋原 BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
}
// Map 中無對(duì)應(yīng)的 BeanDefinition,則直接注冊(cè)
else {
// 已開始創(chuàng)建 Bean
if (hasBeanCreationStarted()) {
synchronized (this.beanDefinitionMap) {
// 將 Bean 對(duì)應(yīng)的 BeanDefinition 放入 beanDefinitionMap 中
this.beanDefinitionMap.put(beanName, beanDefinition);
// 創(chuàng)建新的 beanNames 集合,并將已緩存的 beanName 和新的 beanName 加入該集合
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
// 在手動(dòng)注冊(cè) Bean 的集合中,如果存在同名的 beanName,則將集合中同名的 beanName 刪除
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
// 仍處于啟動(dòng)注冊(cè)階段
else {
// 將當(dāng)前 Bean 對(duì)應(yīng)的 BeanDefinition 放入 beanDefinitionMap 中
this.beanDefinitionMap.put(beanName, beanDefinition);
// 將當(dāng)前 beanName 放入 beanDefinitionNames
this.beanDefinitionNames.add(beanName);
// 刪除手動(dòng)注冊(cè) Bean 集合中同名的 beanName
this.manualSingletonNames.remove(beanName);
}
// 將存儲(chǔ)凍結(jié) BeanDefinition 的 Map 置為 null
this.frozenBeanDefinitionNames = null;
}
// 當(dāng)前注冊(cè)的 BeanDefinition 已在 beanDefinitionMap 中存在,或者其實(shí)例已在存儲(chǔ)單例 Bean 的 Map 中存在
if (oldBeanDefinition != null || containsSingleton(beanName)) {
// 重置 BeanDefinition,主要做一些清理工作
resetBeanDefinition(beanName);
}
}
}
執(zhí)行完 registerBeanDefinition 方法后,Bean 的名稱和對(duì)應(yīng)的 BeanDefinition 就被放入了容器中,后續(xù)獲取 Bean 也是從這個(gè)容器中獲取。
當(dāng)然,DefaultListableBeanFactory 還實(shí)現(xiàn)了 BeanDefinitionRegistry 接口的其它方法,如對(duì) BeanDefinition 進(jìn)行移除、判斷是否存在、獲取數(shù)量等操作,其實(shí)都是圍繞 beanDefinitionMap 這個(gè) Map 進(jìn)行的,這里就不詳細(xì)介紹。
需要注意的是 registerBeanDefinition 方法會(huì)在后面頻繁被調(diào)用,后續(xù)會(huì)逐一提到。
最后
這篇文章主要對(duì)注冊(cè) Bean 的核心方法進(jìn)行討論,但其中涉及到了單例 Bean 實(shí)例注冊(cè),這和當(dāng)前文章的注冊(cè) Bean 不同,當(dāng)前保存的是任意 Bean 的信息,而后者,保存的是單例 Bean 的對(duì)象,我們將在下篇文章詳細(xì)討論。