Spring之IoC篇 - BeanDefinition 的解析阶段(XML 文件)

该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读

Spring 版本:5.1.14.RELEASE

开始阅读这一系列文章之前,建议先查看《深入了解 Spring IoC(面试题)》这一篇文章

该系列其他文章请查看:《死磕 Spring 之 IoC 篇 - 文章导读》

BeanDefinition 的解析阶段(XML 文件)
上一篇文章《BeanDefinition 的加载阶段(XML 文件)》获取到 org.w3c.dom.Document 对象后,需要通过 DefaultBeanDefinitionDocumentReader 进行解析,解析出 XML 文件中定义的 BeanDefinition 并进行注册,先来回顾一下上一篇文章中的这段代码:

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 一个默认实现类

BeanDefinitionDocumentReader 接口
org.springframework.beans.factory.xml.BeanDefinitionDocumentReader,解析 DOM document 中的 BeanDefinition 并注册,代码如下:

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 默认的 BeanDefinitionDocumentReader 实现类,从 XML 文件中解析出 BeanDefinition 并注册

构造函数
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 文件中常用的标签

  1. registerBeanDefinitions 方法
    registerBeanDefinitions(Document doc, XmlReaderContext readerContext) 方法,根据 Document、XmlReaderContext 解析出所有的 BeanDefinition 并注册,方法如下:

@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 } 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> 检查 根标签的命名空间是否为空,或者是 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 的最顶层的标签,也就是 ,然后对其子标签进行解析,这里的过程大致如下:

创建 BeanDefinitionParserDelegate 对象 delegate,并初始化默认值
检查 根标签是否是默认命名空间(xmlns 属性,为空或者是 http://www.springframework.org/schema/beans),是的话进行校验
获取 profile 属性,使用分隔符切分
根据 Spring Environment 进行校验,如果所有 profile 都无效,则不进行注册
解析前处理,空方法,暂时忽略
解析出 XML Document 中的 BeanDefinition 并注册,调用 parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) 方法
解析后处理,空方法,暂时忽略
2. parseBeanDefinitions 方法
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"?>


<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>
在 XML 文件中的标签的 xmlns 可以定义默认的命名空间,xmlns:context 定义 context 的命名空间,xsi:schemaLocation 定义了命名空间对应的 XSD 文件(校验 XML 内容)。

上面的 和 标签的命名空间为 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 的解析器。

  1. parseDefaultElement 方法
    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);
}
}
解析下面四种标签:

标签,例如这么配置:,那么这里会获取到对应的 XML 文件,然后进行相同的处理过程

标签,将 name 对应的 alias 别名进行注册,往 AliasRegistry 注册(BeanDefinitionRegistry 继承了它),也就是说你可以通过别名找到对应的 Bean

标签,解析成 BeanDefinition 并注册,调用 processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 方法

标签,循环处理,和前面的步骤相同

  1. processBeanDefinition 方法
    processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 方法,将 标签解析成 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));
}
}
过程如下:

解析 标签,返回 BeanDefinitionHolder 对象(包含 BeanDefinition、beanName、aliases),调用 BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele) 方法
对该标签进行装饰,和上面处理自定义标签类似,暂时忽略
进行 BeanDefinition 的注册
发出响应事件,通知相关的监听器,已完成该 Bean 标签的解析
BeanDefinitionParserDelegate
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate,解析 XML Document 里面的 BeanDefinition

  1. parseBeanDefinitionElement 方法
    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> 获取标签的 idname 属性
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;

}
过程如下:

计算 BeanDefinition 的 beanName 名称和 aliases 别名集合
获取标签的 id 和 name 属性
将 name 属性全部添加至别名集合 aliases
设置 Bean 的名称 beanName,优先 id 属性,其次 name 属性
检查 beanName 的唯一性
解析 标签相关属性,构造出一个 GenericBeanDefinition 对象,调用 parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) 方法
如果不存在 beanName,则根据 Class 对象的名称生成一个
创建 BeanDefinitionHolder 对象,设置 beanName 名称和 aliases 别名集合,返回
6. parseBeanDefinitionElement 重载方法
parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) 方法,解析 成 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 属性
构建一个 GenericBeanDefinition 对象 bd,设置 parentName 和 beanClass(Class 对象)或者 className(Class 名称)
解析 的各种属性并赋值:scope、abstract、lazy-init、autowire、depends-on、autowire-candidate、primary、init-method、destroy-method、factory-method
解析 的子标签,生成的对象设置到 bd 中
解析 元数据标签,将 key-value 保存至 Map 中
解析 标签,解析成 LookupOverride 对象,用于实现 Bean 中的某个方法
解析 标签,解析成 ReplaceOverride 对象,用于替换 Bean 中的某个方法
解析 构造函数的参数集合标签,将各个参数解析出来,可根据 index 属性进行排序
解析 属性标签,将各个属性解析出来,每个属性对应一个 PropertyValue,添加至 bd 的 MutablePropertyValues 属性中
解析 标签,解析出需要注入的对象 AutowireCandidateQualifier
设置 Bean 的 resource 资源为 XML 文件资源
设置 Bean 的 source 来源为 标签对象
lookup-method,会被解析成 LookupOverride 对象,replaced-method 会被解析成 ReplaceOverride 对象,这两个标签不是很常用

lookup-method:例如一个在一个抽象类中定义了抽象方法,可以通过这个标签定义一个 Bean 实现这个方法,Spring 会动态改变抽象类该方法的实现

replace-method:通过这个标签定义一个 Bean,去覆盖对应的方法,Spring 会动态替换类的这个方法

BeanDefinitionReaderUtils
org.springframework.beans.factory.support.BeanDefinitionReaderUtils,BeanDefinition 的解析过程中的工具类

  1. registerBeanDefinition 方法
    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);
    }
}

}
过程如下:

注册 BeanDefinition,调用 BeanDefinitionRegistry#registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法
注册 alias 别名,调用 BeanDefinitionRegistry#registerAlias(String name, String alias) 方法
这里的 BeanDefinitionRegistry 实现类是 DefaultListableBeanFactory,它是 Spring 底层 IoC 容器,还继承了 SimpleAliasRegistry(AliasRegistry 实现类)

  1. 注册 BeanDefinition
    // 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 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

  2. 注册 alias 别名
    // 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 并注册的整个过程大致如下:

根据 XSD 文件对 XML 文件进行校验
将 XML 文件资源转换成 org.w3c.dom.Document 对象
根据 Document 对象解析 标签,遍历所有的子标签
如果是子标签是默认的命名空间(为空或者 http://www.springframework.org/schema/beans)则进行处理,例如:、、和,其中 会被解析出一个 GenericBeanDefinition 对象,然后进行注册
否则,找到对应的 NamespaceHandler 对象进行解析,例如:<context:component-scan /> 、<context:annotation-config />、<util:list />,这些非默认命名空间的标签都会有对应的 BeanDefinitionParser 解析器
至此,我们通过 XML 文件定义的 Bean 已经转换成了 Bean 的“前身”,也就是 BeanDefinition 对象。接下来会分析在 XML 文件中,非默认命名空间的标签是如何进行处理的。
亚马逊测评 www.yisuping.cn

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值