該系列文章是本人在學(xué)習(xí) Spring 的過(guò)程中總結(jié)下來(lái)的,里面涉及到相關(guān)源碼,可能對(duì)讀者不太友好,請(qǐng)結(jié)合我的源碼注釋 Spring 源碼分析 GitHub 地址 進(jìn)行閱讀
Spring 版本:5.1.14.RELEASE
開(kāi)始閱讀這一系列文章之前,建議先查看《深入了解 Spring IoC(面試題)》這一篇文章
該系列其他文章請(qǐng)查看:《死磕 Spring 之 IoC 篇 - 文章導(dǎo)讀》
上一篇文章《BeanDefinition 的加載階段(XML 文件)》獲取到 org.w3c.dom.Document
對(duì)象后,需要通過(guò) DefaultBeanDefinitionDocumentReader 進(jìn)行解析,解析出 XML 文件中定義的 BeanDefinition 并進(jìn)行注冊(cè),先來(lái)回顧一下上一篇文章中的這段代碼:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // <1> 創(chuàng)建 BeanDefinitionDocumentReader 對(duì)象 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); // <2> 獲取已注冊(cè)的 BeanDefinition 數(shù)量 int countBefore = getRegistry().getBeanDefinitionCount(); // <3> 創(chuàng)建 XmlReaderContext 對(duì)象(讀取 Resource 資源的上下文對(duì)象) // <4> 根據(jù) Document、XmlReaderContext 解析出所有的 BeanDefinition 并注冊(cè) documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); // <5> 計(jì)算新注冊(cè)的 BeanDefinition 數(shù)量 return getRegistry().getBeanDefinitionCount() - countBefore;}
本文開(kāi)始分析第 4
步,BeanDefinition 的解析階段,其中 BeanDefinitionDocumentReader 只有 DefaultBeanDefinitionDocumentReader 一個(gè)默認(rèn)實(shí)現(xiàn)類
org.springframework.beans.factory.xml.BeanDefinitionDocumentReader
,解析 DOM document 中的 BeanDefinition 并注冊(cè),代碼如下:
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 默認(rèn)的 BeanDefinitionDocumentReader 實(shí)現(xiàn)類,從 XML 文件中解析出 BeanDefinition 并注冊(cè)
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";@Nullableprivate XmlReaderContext readerContext;/** * XML 文件的 BeanDefinition 解析器 */@Nullableprivate BeanDefinitionParserDelegate delegate;}
上面定義了 XML 文件中常用的標(biāo)簽
registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
方法,根據(jù) Document、XmlReaderContext 解析出所有的 BeanDefinition 并注冊(cè),方法如下:
@Overridepublic void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; // 獲得 XML Document Root Element // 執(zhí)行注冊(cè) 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 對(duì)象,避免再次調(diào)用當(dāng)前方法時(shí)解析出現(xiàn)問(wèn)題(默認(rèn)值可能不同) BeanDefinitionParserDelegate parent = this.delegate; // <1> 創(chuàng)建 BeanDefinitionParserDelegate 對(duì)象 `delegate`,并初始化默認(rèn)值 this.delegate = createDelegate(getReaderContext(), root, parent); // <2> 檢查 <beans /> 根標(biāo)簽的命名空間是否為空,或者是 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> 使用分隔符切分,可能有多個(gè) `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> 根據(jù) Spring Environment 進(jìn)行校驗(yàn),如果所有 `profile` 都無(wú)效,則不進(jìn)行注冊(cè) 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 并注冊(cè) parseBeanDefinitions(root, this.delegate); // <5> 解析后處理 postProcessXml(root); // 設(shè)置 delegate 回老的 BeanDefinitionParserDelegate 對(duì)象 this.delegate = parent;}
首先獲取 XML Document 的最頂層的標(biāo)簽,也就是 <beans />
,然后對(duì)其子標(biāo)簽進(jìn)行解析,這里的過(guò)程大致如下:
delegate
,并初始化默認(rèn)值<beans />
根標(biāo)簽是否是默認(rèn)命名空間(xmlns 屬性,為空或者是 http://www.springframework.org/schema/beans
),是的話進(jìn)行校驗(yàn)profile
屬性,使用分隔符切分profile
都無(wú)效,則不進(jìn)行注冊(cè)parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
方法parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
方法,解析 XML Document 的最頂層的標(biāo)簽,解析出 BeanDefinition 并注冊(cè),方法如下:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { // <1> 如果根節(jié)點(diǎn)使用默認(rèn)命名空間,執(zhí)行默認(rèn)解析 if (delegate.isDefaultNamespace(root)) { // <1.1> 遍歷所有的子節(jié)點(diǎn) 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> 如果該節(jié)點(diǎn)使用默認(rèn)命名空間,執(zhí)行默認(rèn)解析 if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } // <1.3> 如果該節(jié)點(diǎn)非默認(rèn)命名空間,執(zhí)行自定義解析 else { delegate.parseCustomElement(ele); } } } } // <2> 如果根節(jié)點(diǎn)非默認(rèn)命名空間,執(zhí)行自定義解析 else { delegate.parseCustomElement(root); }}
解析過(guò)程大致如下:
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 文件中的標(biāo)簽的 xmlns
可以定義默認(rèn)的命名空間,xmlns:context
定義 context
的命名空間,xsi:schemaLocation
定義了命名空間對(duì)應(yīng)的 XSD 文件(校驗(yàn) XML 內(nèi)容)。
上面的 <beans />
和 <bean>
標(biāo)簽的命名空間為 http://www.springframework.org/schema/beans
,其中 <context:component-scan />
標(biāo)簽的命名空間為 http://www.springframework.org/schema/context
(不是默認(rèn)命名空間)
本文主要分析默認(rèn)命名空間的解析過(guò)程,其他命名空間(注解相關(guān))在后面進(jìn)行分析,基于 Extensible XML authoring 擴(kuò)展 Spring XML 元素會(huì)進(jìn)入這里,主要是通過(guò) NamespaceHandler 這個(gè)接口實(shí)現(xiàn)的。例如 Spring 集成 Mybatis 項(xiàng)目中的 <mybatis:scan />
就是擴(kuò)展 Spring XML 元素,具體實(shí)現(xiàn)在后面分析;Spring 的<context:component-scan />
最終會(huì)通過(guò) ComponentScanBeanDefinitionParser 進(jìn)行解析。ComponentScanBeanDefinitionParser 是將 @Component 注解標(biāo)注的類轉(zhuǎn)換成 BeanDefinition 的解析器。
parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
方法,處理默認(rèn)命名空間的節(jié)點(diǎn),方法如下:
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 對(duì)應(yīng)的 alias 別名進(jìn)行注冊(cè) processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // 解析 `<bean />` processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // 循環(huán)處理,解析 `<beans />` doRegisterBeanDefinitions(ele); }}
解析下面四種標(biāo)簽:
<import />
標(biāo)簽,例如這么配置:<import resource="dependency-lookup-context.xml"/>
,那么這里會(huì)獲取到對(duì)應(yīng)的 XML 文件,然后進(jìn)行相同的處理過(guò)程
<alias />
標(biāo)簽,將 name 對(duì)應(yīng)的 alias 別名進(jìn)行注冊(cè),往 AliasRegistry 注冊(cè)(BeanDefinitionRegistry 繼承了它),也就是說(shuō)你可以通過(guò)別名找到對(duì)應(yīng)的 Bean
<bean />
標(biāo)簽,解析成 BeanDefinition 并注冊(cè),調(diào)用 processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
方法
<beans />
標(biāo)簽,循環(huán)處理,和前面的步驟相同
processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
方法,將 <bean />
標(biāo)簽解析成 BeanDefinition 并注冊(cè),方法如下:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // <1> 解析 `<bean />` 標(biāo)簽,返回 BeanDefinitionHolder 對(duì)象(包含 BeanDefinition、beanName、aliases) BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { // <2> 對(duì)該標(biāo)簽進(jìn)行裝飾,一般不會(huì),暫時(shí)忽略 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. // <3> 進(jìn)行 BeanDefinition 的注冊(cè) 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> 發(fā)出響應(yīng)事件,通知相關(guān)的監(jiān)聽(tīng)器,已完成該 Bean 標(biāo)簽的解析 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); }}
過(guò)程如下:
<bean />
標(biāo)簽,返回 BeanDefinitionHolder 對(duì)象(包含 BeanDefinition、beanName、aliases),調(diào)用 BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele)
方法org.springframework.beans.factory.xml.BeanDefinitionParserDelegate
,解析 XML Document 里面的 BeanDefinition
parseBeanDefinitionElement(Element ele)
方法,將 XML Document 里面的某個(gè)標(biāo)簽解析成 BeanDefinition,方法如下:
@Nullablepublic BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null);}public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { // <1> 計(jì)算 BeanDefinition 的 `beanName` 名稱和 `aliases` 別名集合 // <1.1> 獲取標(biāo)簽的 `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> 設(shè)置 Bean 的名稱,優(yōu)先 `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 />` 標(biāo)簽相關(guān)屬性,構(gòu)造出一個(gè) GenericBeanDefinition 對(duì)象 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { // <3> 如果不存在 `beanName`,則根據(jù) Class 對(duì)象的名稱生成一個(gè) if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { // 內(nèi)部 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> 創(chuàng)建 BeanDefinitionHolder 對(duì)象,設(shè)置 `beanName` 名稱和 `aliases` 別名集合,返回 String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null;}
過(guò)程如下:
beanName
名稱和 aliases
別名集合id
和 name
屬性name
屬性全部添加至別名集合 aliases
beanName
,優(yōu)先 id
屬性,其次 name
屬性beanName
的唯一性<bean />
標(biāo)簽相關(guān)屬性,構(gòu)造出一個(gè) GenericBeanDefinition 對(duì)象,調(diào)用 parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)
方法beanName
,則根據(jù) Class 對(duì)象的名稱生成一個(gè)beanName
名稱和 aliases
別名集合,返回parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)
方法,解析 <bean />
成 GenericBeanDefinition 對(duì)象,方法如下:
@Nullablepublic 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> 構(gòu)建一個(gè) GenericBeanDefinition 對(duì)象 `bd` AbstractBeanDefinition bd = createBeanDefinition(className, parent); // <3> 解析 `<bean />` 的各種屬性并賦值 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); // 提取 description bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); // <4> 解析 `<bean />` 的子標(biāo)簽,生成的對(duì)象設(shè)置到 `bd` 中 // <4.1> 解析 `<meta />` 元數(shù)據(jù)標(biāo)簽 parseMetaElements(ele, bd); // <4.2> 解析 `<lookup-method />` 標(biāo)簽 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); // <4.3> 解析 `<replaced-method />` 標(biāo)簽 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // <4.4> 解析 `<constructor-arg />` 構(gòu)造函數(shù)的參數(shù)集合標(biāo)簽 parseConstructorArgElements(ele, bd); // <4.5> 解析 `<property />` 屬性標(biāo)簽 parsePropertyElements(ele, bd); // <4.5> 解析 `<qualifier />` 標(biāo)簽 parseQualifierElements(ele, bd); // <5> 設(shè)置 Bean 的 `resource` 資源為 XML 文件資源 bd.setResource(this.readerContext.getResource()); // <6> 設(shè)置 Bean 的 `source` 來(lái)源為 `<bean />` 標(biāo)簽對(duì)象 bd.setSource(extractSource(ele)); return bd; } // ... 省略 catch 各種異常 finally { this.parseState.pop(); } return null;}
過(guò)程如下:
class
和 parent
屬性bd
,設(shè)置 parentName
和 beanClass
(Class 對(duì)象)或者 className
(Class 名稱)<bean />
的各種屬性并賦值:scope、abstract、lazy-init、autowire、depends-on、autowire-candidate、primary、init-method、destroy-method、factory-method<bean />
的子標(biāo)簽,生成的對(duì)象設(shè)置到 bd
中<meta />
元數(shù)據(jù)標(biāo)簽,將 key-value 保存至 Map 中<lookup-method />
標(biāo)簽,解析成 LookupOverride 對(duì)象,用于實(shí)現(xiàn) Bean 中的某個(gè)方法<replaced-method />
標(biāo)簽,解析成 ReplaceOverride 對(duì)象,用于替換 Bean 中的某個(gè)方法<constructor-arg />
構(gòu)造函數(shù)的參數(shù)集合標(biāo)簽,將各個(gè)參數(shù)解析出來(lái),可根據(jù) index 屬性進(jìn)行排序<property />
屬性標(biāo)簽,將各個(gè)屬性解析出來(lái),每個(gè)屬性對(duì)應(yīng)一個(gè) PropertyValue,添加至 bd
的 MutablePropertyValues 屬性中<qualifier />
標(biāo)簽,解析出需要注入的對(duì)象 AutowireCandidateQualifierresource
資源為 XML 文件資源source
來(lái)源為 <bean />
標(biāo)簽對(duì)象lookup-method,會(huì)被解析成 LookupOverride 對(duì)象,replaced-method 會(huì)被解析成 ReplaceOverride 對(duì)象,這兩個(gè)標(biāo)簽不是很常用
lookup-method:例如一個(gè)在一個(gè)抽象類中定義了抽象方法,可以通過(guò)這個(gè)標(biāo)簽定義一個(gè) Bean 實(shí)現(xiàn)這個(gè)方法,Spring 會(huì)動(dòng)態(tài)改變抽象類該方法的實(shí)現(xiàn)
replace-method:通過(guò)這個(gè)標(biāo)簽定義一個(gè) Bean,去覆蓋對(duì)應(yīng)的方法,Spring 會(huì)動(dòng)態(tài)替換類的這個(gè)方法
org.springframework.beans.factory.support.BeanDefinitionReaderUtils
,BeanDefinition 的解析過(guò)程中的工具類
registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
,注冊(cè) BeanDefinition,方法如下:
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // <1> 注冊(cè) BeanDefinition // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // <2> 注冊(cè) alias 別名 // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } }}
過(guò)程如下:
BeanDefinitionRegistry#registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
方法BeanDefinitionRegistry#registerAlias(String name, String alias)
方法這里的 BeanDefinitionRegistry 實(shí)現(xiàn)類是 DefaultListableBeanFactory,它是 Spring 底層 IoC 容器,還繼承了 SimpleAliasRegistry(AliasRegistry 實(shí)現(xiàn)類)
// org.springframework.beans.factory.support.DefaultListableBeanFactory@Overridepublic void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { // 校驗(yàn) beanName 與 beanDefinition 非空 Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); // <1> 校驗(yàn) BeanDefinition // 這是注冊(cè)前的最后一次校驗(yàn)了,主要是對(duì)屬性 methodOverrides 進(jìn)行校驗(yàn) 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> 如果已經(jīng)存在 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 { // 檢測(cè)創(chuàng)建 Bean 階段是否已經(jīng)開(kāi)啟,如果開(kāi)啟了則需要對(duì) beanDefinitionMap 進(jìn)行并發(fā)控制 if (hasBeanCreationStarted()) { // beanDefinitionMap 為全局變量,避免并發(fā)情況 // 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 中,保證注冊(cè)順序 this.beanDefinitionNames.add(beanName); // 從 manualSingletonNames 移除 beanName removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } // <5> 重新設(shè)置 beanName 對(duì)應(yīng)的緩存 if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); }}
邏輯不復(fù)雜,主要是對(duì) beanName
和該 BeanDefinition 對(duì)象的校驗(yàn),最終將其映射保存在 beanDefinitionMap
中(ConcurrentHashMap),key 就是 beanName
// org.springframework.core.SimpleAliasRegistry@Overridepublic void registerAlias(String name, String alias) { // 校驗(yàn) 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 已注冊(cè)的 beanName String registeredName = this.aliasMap.get(alias); // 已存在 if (registeredName != null) { // 相同,則 return ,無(wú)需重復(fù)注冊(cè) 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 + "'"); } } // 校驗(yàn),是否存在循環(huán)指向 checkForAliasCircle(name, alias); // 注冊(cè) alias this.aliasMap.put(alias, name); if (logger.isTraceEnabled()) { logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'"); } } }}
邏輯不復(fù)雜,將 alias
與 beanName
映射保存至 aliasMap
中(ConcurrentHashMap)
解析出 XML 文件中的 BeanDefinition 并注冊(cè)的整個(gè)過(guò)程大致如下:
org.w3c.dom.Document
對(duì)象<beans />
標(biāo)簽,遍歷所有的子標(biāo)簽http://www.springframework.org/schema/beans
)則進(jìn)行處理,例如:<import>
、<alias />
、<bean />
和<beans />
,其中 <bean />
會(huì)被解析出一個(gè) GenericBeanDefinition 對(duì)象,然后進(jìn)行注冊(cè)<context:component-scan />
、<context:annotation-config />
、<util:list />
,這些非默認(rèn)命名空間的標(biāo)簽都會(huì)有對(duì)應(yīng)的 BeanDefinitionParser 解析器至此,我們通過(guò) XML 文件定義的 Bean 已經(jīng)轉(zhuǎn)換成了 Bean 的“前身”,也就是 BeanDefinition 對(duì)象。接下來(lái)會(huì)分析在 XML 文件中,非默認(rèn)命名空間的標(biāo)簽是如何進(jìn)行處理的。
聯(lián)系客服