在上一章中,我留了一個 "BeanDefinition註冊到registry" 的尾巴還沒分析,這邊我把代碼入口從新放到下面,以便於回顧:java
/** * 經過解析器delegate去處理給定的bean element, 並解析出相應的bean Definition, 註冊到工廠中 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 經過delegate解析bean定義, 獲取到一個BeanDefinitionHolder實例
// 這個實例, 其實就表明了xml文件中的一個完整的bean標籤對應的Bean Definition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
// 若是bdHolder不爲空, 說明解析成功了, 以後就是註冊環節了
// 註冊環節咱們留着在下一篇中詳細展開
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 註冊最終的BeanDefinition到工廠
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
複製代碼
咱們要關注的是:BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
緩存
要註冊BeanDefinition到工廠,首先咱們得獲取到工廠,這裏是經過讀取器上下文來獲取到的 getReaderContext().getRegistry()
ide
還記得咱們第四章分析的:建立讀取器上下文的代碼麼,讀取器上下文內部是封裝了讀取器實例的,這就意味着咱們可以經過上下文獲取到讀取器。工具
緊接着,咱們在第一章分析的,建立讀取器時會傳入一個 registry 類型的參數,所以經過讀取器咱們又可以獲取到 registry。ui
所以,咱們就可以經過讀取器上下文獲取到 registry。this
BeanDefinitionReaderUtils.registerBeanDefinition()spa
這裏是調用了一個工具類來實現註冊的流程線程
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
// 獲取到Bean的惟一標識
String beanName = definitionHolder.getBeanName();
// 重點!!!!
// 將 bean 定義真正註冊到 Bean 工廠中
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 若是存在別名, 那麼會註冊別名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
複製代碼
咱們接着深刻到 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
這部分的邏輯:debug
因爲對於 registry 的實現是採用的 —— DefaultListableBeanFactory,所以咱們看看這個類對於 registerBeanDefinition() 的實現便可。日誌
下面的代碼有些長,咱們挑關鍵的部分分析便可:
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
// 惟一標識不能爲空
Assert.hasText(beanName, "Bean name must not be empty");
// 確保Bean定義不能爲空
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
// 若是Bean定義是 AbstractBeanDefinition 類型, 那麼會進行一個驗證邏輯
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex);
}
}
// 咱們的Bean定義是挨個被解析而後註冊到工廠中的
// 這就意味着工廠中可能已經存在其餘Bean定義
// 所以這裏會先嚐試從工廠中獲取一下咱們要註冊的bean定義
// 確保工廠中是不存在這個bean定義的
// 這裏存放 惟一標識+BeanDefinition 的容器beanDefinitionMap是 concurrentHashMap
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
// 若是已經存在相應的惟一標識了
if (existingDefinition != null) {
// 那麼爲判斷是否容許 BeanDefinition 的覆蓋
// 若是不容許就拋出異常
// 通常都是不容許的
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
// 若是容許覆蓋, 那麼會進行一個bean定義角色的判斷
// 若是已經存在的bean定義的角色小於當前要存放bean定義的角色, 那麼會進行一個日誌打印
// 通常在開發中也不多會進入這個邏輯
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
// 若是兩者(已經存在的bean定義和要覆蓋的bean定義)不相同
// 那麼打印一個日誌
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else { // 若是是其餘的極端狀況, 也會打印一個日誌
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
// 進行一個bean定義的覆蓋,放置key-value到map中
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else { // 若是 concurrentHashMap 中不存在相應的bean定義鍵值對
// 那麼會檢查這個工廠中bean的建立階段是否已經啓動
// 也就是這個工廠中的全部bean它是否被標記爲 created
// 若是已經啓動
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
// 那麼會進行一個同步
// 防止多個線程同時進行註冊的操做
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else { // 不然就會直接註冊, 不須要進行同步
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
// 重置 BeanDefinition 緩存的處理
resetBeanDefinition(beanName);
}
}
複製代碼
當上面這個方法執行完畢後,工廠中的 BeanDefinitionMap 這個容器就已經存放了一個key-value鍵值對,key=惟一標識、value=beanDefinition。
當整個解析、註冊的事件處理完畢後,咱們返回到一開始給出的那個方法中:
/** * 經過解析器delegate去處理給定的bean element, 並解析出相應的bean Definition, 註冊到工廠中 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 經過delegate解析bean定義, 獲取到一個BeanDefinitionHolder實例
// 這個實例, 其實就表明了xml文件中的一個完整的bean標籤對應的Bean Definition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
// 若是bdHolder不爲空, 說明解析成功了, 以後就是註冊環節了
// 註冊環節咱們留着在下一篇中詳細展開
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 註冊最終的BeanDefinition到工廠
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);
}
// 發送事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
複製代碼
咱們看到最後執行的方法:getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
這裏採用了一個觀察者模式,當特定的事件觸發(成功完成Bean定義的解析、註冊),那麼會調用觀察者類(讀取器上下文)的方法,執行一些特定邏輯。
那麼這裏,整個 Spring 對 Bean 的解析、裝配流程就分析完畢了。從宏觀上來看,beanDefinitionReader.loadBeanDefinitions()
這個邏輯就完成了。但要注意,截止到目前,咱們只是在工廠中註冊了Bean Definition,並無對其完成一個實例化的過程。 實例化的過程還要在後續的邏輯中才開始執行。
因而可知,Spring 對外提供的 API 接口僅僅是冰山一角,底層的實現就如同大海同樣深不可測。
那麼在下一章將帶來:defaultListableBeanFactory.getBean("student", Student.class);
,也就是依賴注入的詳細分析。