該系列文章是本人在學習 Spring 的過程當中總結下來的,裏面涉及到相關源碼,可能對讀者不太友好,請結合個人源碼註釋 Spring 源碼分析 GitHub 地址 進行閱讀html
Spring 版本:5.1.14.RELEASEjava
開始閱讀這一系列文章以前,建議先查看《深刻了解 Spring IoC(面試題)》這一篇文章node
該系列其餘文章請查看:《死磕 Spring 之 IoC 篇 - 文章導讀》git
上一篇文章《BeanDefinition 的加載階段(XML 文件)》獲取到 org.w3c.dom.Document
對象後,須要經過 DefaultBeanDefinitionDocumentReader 進行解析,解析出 XML 文件中定義的 BeanDefinition 並進行註冊,先來回顧一下上一篇文章中的這段代碼:github
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // <1> 建立 BeanDefinitionDocumentReader 對象 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); // <2> 獲取已註冊的 BeanDefinition 數量 int countBefore = getRegistry().getBeanDefinitionCount(); // <3> 建立 XmlReaderContext 對象(讀取 Resource 資源的上下文對象) // <4> 根據 Document、XmlReaderContext 解析出全部的 BeanDefinition 並註冊 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); // <5> 計算新註冊的 BeanDefinition 數量 return getRegistry().getBeanDefinitionCount() - countBefore; }
本文開始分析第 4
步,BeanDefinition 的解析階段,其中 BeanDefinitionDocumentReader 只有 DefaultBeanDefinitionDocumentReader 一個默認實現類面試
org.springframework.beans.factory.xml.BeanDefinitionDocumentReader
,解析 DOM document 中的 BeanDefinition 並註冊,代碼以下:spring
public interface BeanDefinitionDocumentReader { /** * Read bean definitions from the given DOM document and * register them with the registry in the given reader context. * @param doc the DOM document * @param readerContext the current context of the reader * (includes the target registry and the resource being parsed) * @throws BeanDefinitionStoreException in case of parsing errors */ void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) throws BeanDefinitionStoreException; }
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader
,Spring 默認的 BeanDefinitionDocumentReader 實現類,從 XML 文件中解析出 BeanDefinition 並註冊express
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { /** bean */ public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT; public static final String NESTED_BEANS_ELEMENT = "beans"; public static final String ALIAS_ELEMENT = "alias"; public static final String NAME_ATTRIBUTE = "name"; public static final String ALIAS_ATTRIBUTE = "alias"; public static final String IMPORT_ELEMENT = "import"; public static final String RESOURCE_ATTRIBUTE = "resource"; public static final String PROFILE_ATTRIBUTE = "profile"; @Nullable private XmlReaderContext readerContext; /** * XML 文件的 BeanDefinition 解析器 */ @Nullable private BeanDefinitionParserDelegate delegate; }
上面定義了 XML 文件中經常使用的標籤緩存
registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
方法,根據 Document、XmlReaderContext 解析出全部的 BeanDefinition 並註冊,方法以下:mybatis
@Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; // 得到 XML Document Root Element // 執行註冊 BeanDefinition doRegisterBeanDefinitions(doc.getDocumentElement()); } /** * Register each bean definition within the given root {@code <beans/>} element. */ @SuppressWarnings("deprecation") // for Environment.acceptsProfiles(String...) protected void doRegisterBeanDefinitions(Element root) { // 記錄老的 BeanDefinitionParserDelegate 對象,避免再次調用當前方法時解析出現問題(默認值可能不一樣) BeanDefinitionParserDelegate parent = this.delegate; // <1> 建立 BeanDefinitionParserDelegate 對象 `delegate`,並初始化默認值 this.delegate = createDelegate(getReaderContext(), root, parent); // <2> 檢查 <beans /> 根標籤的命名空間是否爲空,或者是 http://www.springframework.org/schema/beans if (this.delegate.isDefaultNamespace(root)) { // <2.1> 獲取 `profile` 屬性 String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { // <2.2> 使用分隔符切分,可能有多個 `profile` String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); // We cannot use Profiles.of(...) since profile expressions are not supported // in XML config. See SPR-12458 for details. // <2.3> 根據 Spring Environment 進行校驗,若是全部 `profile` 都無效,則不進行註冊 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isDebugEnabled()) { logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } // <3> 解析前處理 preProcessXml(root); // <4> 解析出 XML Document 中的 BeanDefinition 並註冊 parseBeanDefinitions(root, this.delegate); // <5> 解析後處理 postProcessXml(root); // 設置 delegate 回老的 BeanDefinitionParserDelegate 對象 this.delegate = parent; }
首先獲取 XML Document 的最頂層的標籤,也就是 <beans />
,而後對其子標籤進行解析,這裏的過程大體以下:
delegate
,並初始化默認值<beans />
根標籤是不是默認命名空間(xmlns 屬性,爲空或者是 http://www.springframework.org/schema/beans
),是的話進行校驗
profile
屬性,使用分隔符切分profile
都無效,則不進行註冊parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
方法parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
方法,解析 XML Document 的最頂層的標籤,解析出 BeanDefinition 並註冊,方法以下:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { // <1> 若是根節點使用默認命名空間,執行默認解析 if (delegate.isDefaultNamespace(root)) { // <1.1> 遍歷全部的子節點 NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; // <1.2> 若是該節點使用默認命名空間,執行默認解析 if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } // <1.3> 若是該節點非默認命名空間,執行自定義解析 else { delegate.parseCustomElement(ele); } } } } // <2> 若是根節點非默認命名空間,執行自定義解析 else { delegate.parseCustomElement(root); } }
解析過程大體以下:
parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
方法BeanDefinitionParserDelegate#parseCustomElement(Element ele)
方法BeanDefinitionParserDelegate#parseCustomElement(Element ele)
方法命名空間是什麼?
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.geekbang.thinking.in.spring.ioc.overview" /> <bean id="user" class="org.geekbang.thinking.in.spring.ioc.overview.domain.User"> <property name="id" value="1"/> <property name="name" value="小馬哥"/> </bean> </beans>
在 XML 文件中的標籤的 xmlns
能夠定義默認的命名空間,xmlns:context
定義 context
的命名空間,xsi:schemaLocation
定義了命名空間對應的 XSD 文件(校驗 XML 內容)。
上面的 <beans />
和 <bean>
標籤的命名空間爲 http://www.springframework.org/schema/beans
,其中 <context:component-scan />
標籤的命名空間爲 http://www.springframework.org/schema/context
(不是默認命名空間)
本文主要分析默認命名空間的解析過程,其餘命名空間(註解相關)在後面進行分析,基於 Extensible XML authoring 擴展 Spring XML 元素會進入這裏,主要是經過 NamespaceHandler 這個接口實現的。例如 Spring 集成 Mybatis 項目中的 <mybatis:scan />
就是擴展 Spring XML 元素,具體實如今後面分析;Spring 的<context:component-scan />
最終會經過 ComponentScanBeanDefinitionParser 進行解析。ComponentScanBeanDefinitionParser 是將 @Component 註解標註的類轉換成 BeanDefinition 的解析器。
parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
方法,處理默認命名空間的節點,方法以下:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // 解析 `<import />` importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // 解析 `<alias />`,將 name 對應的 alias 別名進行註冊 processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // 解析 `<bean />` processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // 循環處理,解析 `<beans />` doRegisterBeanDefinitions(ele); } }
解析下面四種標籤:
<import />
標籤,例如這麼配置:<import resource="dependency-lookup-context.xml"/>
,那麼這裏會獲取到對應的 XML 文件,而後進行相同的處理過程
<alias />
標籤,將 name 對應的 alias 別名進行註冊,往 AliasRegistry 註冊(BeanDefinitionRegistry 繼承了它),也就是說你能夠經過別名找到對應的 Bean
<bean />
標籤,解析成 BeanDefinition 並註冊,調用 processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
方法
<beans />
標籤,循環處理,和前面的步驟相同
processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
方法,將 <bean />
標籤解析成 BeanDefinition 並註冊,方法以下:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // <1> 解析 `<bean />` 標籤,返回 BeanDefinitionHolder 對象(包含 BeanDefinition、beanName、aliases) BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { // <2> 對該標籤進行裝飾,通常不會,暫時忽略 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. // <3> 進行 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. // <4> 發出響應事件,通知相關的監聽器,已完成該 Bean 標籤的解析 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
過程以下:
<bean />
標籤,返回 BeanDefinitionHolder 對象(包含 BeanDefinition、beanName、aliases),調用 BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele)
方法org.springframework.beans.factory.xml.BeanDefinitionParserDelegate
,解析 XML Document 裏面的 BeanDefinition
parseBeanDefinitionElement(Element ele)
方法,將 XML Document 裏面的某個標籤解析成 BeanDefinition,方法以下:
@Nullable public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { // <1> 計算 BeanDefinition 的 `beanName` 名稱和 `aliases` 別名集合 // <1.1> 獲取標籤的 `id` 和 `name` 屬性 String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); // <1.2> 將 `name` 屬性所有添加至別名集合 List<String> aliases = new ArrayList<>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } // <1.3> 設置 Bean 的名稱,優先 `id` 屬性,其次 `name` 屬性 String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); // 移除出別名集合 if (logger.isTraceEnabled()) { logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } // <1.4> 檢查 `beanName` 的惟一性 if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } // <2> 解析 `<bean />` 標籤相關屬性,構造出一個 GenericBeanDefinition 對象 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { // <3> 若是不存在 `beanName`,則根據 Class 對象的名稱生成一個 if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { // 內部 Bean // <3.1> 生成惟一的 `beanName` beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { // <3.2> 生成惟一的 beanName beanName = this.readerContext.generateBeanName(beanDefinition); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isTraceEnabled()) { logger.trace("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(), ele); return null; } } // <4> 建立 BeanDefinitionHolder 對象,設置 `beanName` 名稱和 `aliases` 別名集合,返回 String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
過程以下:
beanName
名稱和 aliases
別名集合
id
和 name
屬性name
屬性所有添加至別名集合 aliases
beanName
,優先 id
屬性,其次 name
屬性beanName
的惟一性<bean />
標籤相關屬性,構造出一個 GenericBeanDefinition 對象,調用 parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)
方法beanName
,則根據 Class 對象的名稱生成一個beanName
名稱和 aliases
別名集合,返回parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)
方法,解析 <bean />
成 GenericBeanDefinition 對象,方法以下:
@Nullable public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, @Nullable BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); // <1> 獲取 `class` 和 `parent` 屬性 String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } try { // <2> 構建一個 GenericBeanDefinition 對象 `bd` AbstractBeanDefinition bd = createBeanDefinition(className, parent); // <3> 解析 `<bean />` 的各類屬性並賦值 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); // 提取 description bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); // <4> 解析 `<bean />` 的子標籤,生成的對象設置到 `bd` 中 // <4.1> 解析 `<meta />` 元數據標籤 parseMetaElements(ele, bd); // <4.2> 解析 `<lookup-method />` 標籤 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); // <4.3> 解析 `<replaced-method />` 標籤 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // <4.4> 解析 `<constructor-arg />` 構造函數的參數集合標籤 parseConstructorArgElements(ele, bd); // <4.5> 解析 `<property />` 屬性標籤 parsePropertyElements(ele, bd); // <4.5> 解析 `<qualifier />` 標籤 parseQualifierElements(ele, bd); // <5> 設置 Bean 的 `resource` 資源爲 XML 文件資源 bd.setResource(this.readerContext.getResource()); // <6> 設置 Bean 的 `source` 來源爲 `<bean />` 標籤對象 bd.setSource(extractSource(ele)); return bd; } // ... 省略 catch 各類異常 finally { this.parseState.pop(); } return null; }
過程以下:
class
和 parent
屬性bd
,設置 parentName
和 beanClass
(Class 對象)或者 className
(Class 名稱)<bean />
的各類屬性並賦值:scope、abstract、lazy-init、autowire、depends-on、autowire-candidate、primary、init-method、destroy-method、factory-method<bean />
的子標籤,生成的對象設置到 bd
中
<meta />
元數據標籤,將 key-value 保存至 Map 中<lookup-method />
標籤,解析成 LookupOverride 對象,用於實現 Bean 中的某個方法<replaced-method />
標籤,解析成 ReplaceOverride 對象,用於替換 Bean 中的某個方法<constructor-arg />
構造函數的參數集合標籤,將各個參數解析出來,可根據 index 屬性進行排序<property />
屬性標籤,將各個屬性解析出來,每一個屬性對應一個 PropertyValue,添加至 bd
的 MutablePropertyValues 屬性中<qualifier />
標籤,解析出須要注入的對象 AutowireCandidateQualifierresource
資源爲 XML 文件資源source
來源爲 <bean />
標籤對象lookup-method,會被解析成 LookupOverride 對象,replaced-method 會被解析成 ReplaceOverride 對象,這兩個標籤不是很經常使用
lookup-method:例如一個在一個抽象類中定義了抽象方法,能夠經過這個標籤訂義一個 Bean 實現這個方法,Spring 會動態改變抽象類該方法的實現
replace-method:經過這個標籤訂義一個 Bean,去覆蓋對應的方法,Spring 會動態替換類的這個方法
org.springframework.beans.factory.support.BeanDefinitionReaderUtils
,BeanDefinition 的解析過程當中的工具類
registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
,註冊 BeanDefinition,方法以下:
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // <1> 註冊 BeanDefinition // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // <2> 註冊 alias 別名 // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
過程以下:
BeanDefinitionRegistry#registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
方法BeanDefinitionRegistry#registerAlias(String name, String alias)
方法這裏的 BeanDefinitionRegistry 實現類是 DefaultListableBeanFactory,它是 Spring 底層 IoC 容器,還繼承了 SimpleAliasRegistry(AliasRegistry 實現類)
// org.springframework.beans.factory.support.DefaultListableBeanFactory @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { // 校驗 beanName 與 beanDefinition 非空 Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); // <1> 校驗 BeanDefinition // 這是註冊前的最後一次校驗了,主要是對屬性 methodOverrides 進行校驗 if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } // <2> 從緩存中獲取指定 beanName 的 BeanDefinition BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); // <3> 若是已經存在 if (existingDefinition != null) { // 若是存在可是不容許覆蓋,拋出異常 if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } // 覆蓋 beanDefinition 大於 被覆蓋的 beanDefinition 的 ROLE ,打印 info 日誌 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 + "]"); } } // 覆蓋 beanDefinition 與 被覆蓋的 beanDefinition 不相同,打印 debug 日誌 else if (!beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } // 其它,打印 debug 日誌 else { if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } // <4> 若是未存在 else { // 檢測建立 Bean 階段是否已經開啓,若是開啓了則須要對 beanDefinitionMap 進行併發控制 if (hasBeanCreationStarted()) { // beanDefinitionMap 爲全局變量,避免併發狀況 // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { // 添加到 BeanDefinition 到 beanDefinitionMap 中 this.beanDefinitionMap.put(beanName, beanDefinition); // 添加 beanName 到 beanDefinitionNames 中 List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; // 從 manualSingletonNames 移除 beanName removeManualSingletonName(beanName); } } else { // 添加到 BeanDefinition 到 beanDefinitionMap 中 // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); // 添加 beanName 到 beanDefinitionNames 中,保證註冊順序 this.beanDefinitionNames.add(beanName); // 從 manualSingletonNames 移除 beanName removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } // <5> 從新設置 beanName 對應的緩存 if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
邏輯不復雜,主要是對 beanName
和該 BeanDefinition 對象的校驗,最終將其映射保存在 beanDefinitionMap
中(ConcurrentHashMap),key 就是 beanName
// org.springframework.core.SimpleAliasRegistry @Override public void registerAlias(String name, String alias) { // 校驗 name 、 alias Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); synchronized (this.aliasMap) { // name == alias 則去掉alias if (alias.equals(name)) { this.aliasMap.remove(alias); if (logger.isDebugEnabled()) { logger.debug("Alias definition '" + alias + "' ignored since it points to same name"); } } else { // 獲取 alias 已註冊的 beanName String registeredName = this.aliasMap.get(alias); // 已存在 if (registeredName != null) { // 相同,則 return ,無需重複註冊 if (registeredName.equals(name)) { // An existing alias - no need to re-register return; } // 不容許覆蓋,則拋出 IllegalStateException 異常 if (!allowAliasOverriding()) { throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); } if (logger.isDebugEnabled()) { logger.debug("Overriding alias '" + alias + "' definition for registered name '" + registeredName + "' with new target name '" + name + "'"); } } // 校驗,是否存在循環指向 checkForAliasCircle(name, alias); // 註冊 alias this.aliasMap.put(alias, name); if (logger.isTraceEnabled()) { logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'"); } } } }
邏輯不復雜,將 alias
與 beanName
映射保存至 aliasMap
中(ConcurrentHashMap)
解析出 XML 文件中的 BeanDefinition 並註冊的整個過程大體以下:
org.w3c.dom.Document
對象<beans />
標籤,遍歷全部的子標籤
http://www.springframework.org/schema/beans
)則進行處理,例如:<import>
、<alias />
、<bean />
和<beans />
,其中 <bean />
會被解析出一個 GenericBeanDefinition 對象,而後進行註冊<context:component-scan />
、<context:annotation-config />
、<util:list />
,這些非默認命名空間的標籤都會有對應的 BeanDefinitionParser 解析器至此,咱們經過 XML 文件定義的 Bean 已經轉換成了 Bean 的「前身」,也就是 BeanDefinition 對象。接下來會分析在 XML 文件中,非默認命名空間的標籤是如何進行處理的。