免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
死磕Spring之IoC篇 - BeanDefinition 的解析階段(XML 文件)

該系列文章是本人在學(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 文件)

上一篇文章《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)類

BeanDefinitionDocumentReader 接口

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;}

DefaultBeanDefinitionDocumentReader

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader,Spring 默認(rèn)的 BeanDefinitionDocumentReader 實(shí)現(xiàn)類,從 XML 文件中解析出 BeanDefinition 并注冊(cè)

構(gòu)造函數(shù)

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)簽

1. registerBeanDefinitions 方法

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ò)程大致如下:

  1. 創(chuàng)建 BeanDefinitionParserDelegate 對(duì)象 delegate,并初始化默認(rèn)值
  2. 檢查 <beans /> 根標(biāo)簽是否是默認(rèn)命名空間(xmlns 屬性,為空或者是 http://www.springframework.org/schema/beans),是的話進(jìn)行校驗(yàn)
    1. 獲取 profile 屬性,使用分隔符切分
    2. 根據(jù) Spring Environment 進(jìn)行校驗(yàn),如果所有 profile 都無(wú)效,則不進(jìn)行注冊(cè)
  3. 解析前處理,空方法,暫時(shí)忽略
  4. 解析出 XML Document 中的 BeanDefinition 并注冊(cè),調(diào)用 parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) 方法
  5. 解析后處理,空方法,暫時(shí)忽略

2. parseBeanDefinitions 方法

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ò)程大致如下:

  1. 如果根節(jié)點(diǎn)使用默認(rèn)命名空間,執(zhí)行默認(rèn)解析
    1. 遍歷所有的子節(jié)點(diǎn)
    2. 如果該節(jié)點(diǎn)使用默認(rèn)命名空間,執(zhí)行默認(rèn)解析,調(diào)用 parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 方法
    3. 如果該節(jié)點(diǎn)非默認(rèn)命名空間,執(zhí)行自定義解析,調(diào)用 BeanDefinitionParserDelegate#parseCustomElement(Element ele) 方法
  2. 如果根節(jié)點(diǎn)非默認(rèn)命名空間,執(zhí)行自定義解析,調(diào)用 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 的解析器。

3. parseDefaultElement 方法

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)處理,和前面的步驟相同

4. processBeanDefinition 方法

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ò)程如下:

  1. 解析 <bean /> 標(biāo)簽,返回 BeanDefinitionHolder 對(duì)象(包含 BeanDefinition、beanName、aliases),調(diào)用 BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele) 方法
  2. 對(duì)該標(biāo)簽進(jìn)行裝飾,和上面處理自定義標(biāo)簽類似,暫時(shí)忽略
  3. 進(jìn)行 BeanDefinition 的注冊(cè)
  4. 發(fā)出響應(yīng)事件,通知相關(guān)的監(jiān)聽(tīng)器,已完成該 Bean 標(biāo)簽的解析

BeanDefinitionParserDelegate

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate,解析 XML Document 里面的 BeanDefinition

5. parseBeanDefinitionElement 方法

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ò)程如下:

  1. 計(jì)算 BeanDefinition 的 beanName 名稱和 aliases 別名集合
    1. 獲取標(biāo)簽的 idname 屬性
    2. name 屬性全部添加至別名集合 aliases
    3. 設(shè)置 Bean 的名稱 beanName,優(yōu)先 id 屬性,其次 name 屬性
    4. 檢查 beanName 的唯一性
  2. 解析 <bean /> 標(biāo)簽相關(guān)屬性,構(gòu)造出一個(gè) GenericBeanDefinition 對(duì)象,調(diào)用 parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) 方法
  3. 如果不存在 beanName,則根據(jù) Class 對(duì)象的名稱生成一個(gè)
  4. 創(chuàng)建 BeanDefinitionHolder 對(duì)象,設(shè)置 beanName 名稱和 aliases 別名集合,返回

6. parseBeanDefinitionElement 重載方法

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ò)程如下:

  1. 獲取 classparent 屬性
  2. 構(gòu)建一個(gè) GenericBeanDefinition 對(duì)象 bd,設(shè)置 parentNamebeanClass(Class 對(duì)象)或者 className(Class 名稱)
  3. 解析 <bean /> 的各種屬性并賦值:scope、abstract、lazy-init、autowire、depends-on、autowire-candidate、primary、init-method、destroy-method、factory-method
  4. 解析 <bean /> 的子標(biāo)簽,生成的對(duì)象設(shè)置到 bd
    1. 解析 <meta /> 元數(shù)據(jù)標(biāo)簽,將 key-value 保存至 Map 中
    2. 解析 <lookup-method /> 標(biāo)簽,解析成 LookupOverride 對(duì)象,用于實(shí)現(xiàn) Bean 中的某個(gè)方法
    3. 解析 <replaced-method /> 標(biāo)簽,解析成 ReplaceOverride 對(duì)象,用于替換 Bean 中的某個(gè)方法
    4. 解析 <constructor-arg /> 構(gòu)造函數(shù)的參數(shù)集合標(biāo)簽,將各個(gè)參數(shù)解析出來(lái),可根據(jù) index 屬性進(jìn)行排序
    5. 解析 <property /> 屬性標(biāo)簽,將各個(gè)屬性解析出來(lái),每個(gè)屬性對(duì)應(yīng)一個(gè) PropertyValue,添加至 bd 的 MutablePropertyValues 屬性中
    6. 解析 <qualifier /> 標(biāo)簽,解析出需要注入的對(duì)象 AutowireCandidateQualifier
  5. 設(shè)置 Bean 的 resource 資源為 XML 文件資源
  6. 設(shè)置 Bean 的 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è)方法

BeanDefinitionReaderUtils

org.springframework.beans.factory.support.BeanDefinitionReaderUtils,BeanDefinition 的解析過(guò)程中的工具類

7. registerBeanDefinition 方法

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ò)程如下:

  1. 注冊(cè) BeanDefinition,調(diào)用 BeanDefinitionRegistry#registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法
  2. 注冊(cè) alias 別名,調(diào)用 BeanDefinitionRegistry#registerAlias(String name, String alias) 方法

這里的 BeanDefinitionRegistry 實(shí)現(xiàn)類是 DefaultListableBeanFactory,它是 Spring 底層 IoC 容器,還繼承了 SimpleAliasRegistry(AliasRegistry 實(shí)現(xiàn)類)

8. 注冊(cè) BeanDefinition

// 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

9. 注冊(cè) alias 別名

// 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ù)雜,將 aliasbeanName 映射保存至 aliasMap 中(ConcurrentHashMap)

總結(jié)

解析出 XML 文件中的 BeanDefinition 并注冊(cè)的整個(gè)過(guò)程大致如下:

  1. 根據(jù) XSD 文件對(duì) XML 文件進(jìn)行校驗(yàn)
  2. 將 XML 文件資源轉(zhuǎn)換成 org.w3c.dom.Document 對(duì)象
  3. 根據(jù) Document 對(duì)象解析 <beans /> 標(biāo)簽,遍歷所有的子標(biāo)簽
    1. 如果是子標(biāo)簽是默認(rèn)的命名空間(為空或者 http://www.springframework.org/schema/beans)則進(jìn)行處理,例如:<import>、<alias />、<bean /><beans />,其中 <bean /> 會(huì)被解析出一個(gè) GenericBeanDefinition 對(duì)象,然后進(jìn)行注冊(cè)
    2. 否則,找到對(duì)應(yīng)的 NamespaceHandler 對(duì)象進(jìn)行解析,例如:<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)行處理的。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Spring默認(rèn)標(biāo)簽的解析
SpringIOC源碼解析(5)—— 通過(guò)document對(duì)象解析出BeanDefinition實(shí)例
Spring源碼淺析 -- XML配置文件的載入與解析
SpringMVC 源代碼深度解析<context:component
Spring Security3源碼分析-Spring Security
Spring框架之beans源碼完全解析
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服