美文网首页IT@程序员猿媛
【Spring 笔记】Bean 解析相关整理

【Spring 笔记】Bean 解析相关整理

作者: 58bc06151329 | 来源:发表于2019-09-20 14:52 被阅读0次

文前说明

作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。

1. 概述

  • Spring 提供有两种解析 Bean 的方式。
    • 如果根节点或者子节点采用默认命名空间,则调用 parseDefaultElement() 方法,进行 默认标签解析
    • 否则,调用 BeanDefinitionParserDelegate#parseCustomElement() 方法,进行 自定义解析
// DefaultBeanDefinitionDocumentReader.java

public static final String IMPORT_ELEMENT = "import";
public static final String ALIAS_ATTRIBUTE = "alias";
public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT;
public static final String NESTED_BEANS_ELEMENT = "beans";

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // import
        importBeanDefinitionResource(ele);
    } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // alias
        processAliasRegistration(ele);
    } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // bean
        processBeanDefinition(ele, delegate);
    } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // beans
        // recurse
        doRegisterBeanDefinitions(ele);
    }
}

2. 原理

2.1 默认标签解析

  • 例如:<bean id="studentService" class="org.springframework.core.StudentService" />

2.1.1 解析 import 标签

  • Spring 提供了一个分模块的思路,将配置分到不同的模块,再利用 import 标签导入。
    • 如果有配置需要修改直接修改相应配置文件即可。
    • 若有新的模块需要引入直接增加 import 即可。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <import resource="spring-student.xml"/>
    <import resource="spring-student-dtd.xml"/>
</beans>

2.1.1.1 importBeanDefinitionResource

// DefaultBeanDefinitionDocumentReader.java

/**
 * Parse an "import" element and load the bean definitions
 * from the given resource into the bean factory.
 */
protected void importBeanDefinitionResource(Element ele) {
    // 1. 获取 resource 的属性值
    String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
    // 为空,直接退出
    if (!StringUtils.hasText(location)) {
        getReaderContext().error("Resource location must not be empty", ele); // 使用 problemReporter 报错
        return;
    }

    // 2. 解析系统属性,格式如 :"${user.dir}"
    // Resolve system properties: e.g. "${user.dir}"
    location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);

    // 实际 Resource 集合,即 import 的地址,有哪些 Resource 资源
    Set<Resource> actualResources = new LinkedHashSet<>(4);

    // 3. 判断 location 是相对路径还是绝对路径
    // Discover whether the location is an absolute or relative URI
    boolean absoluteLocation = false;
    try {
        absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
    } catch (URISyntaxException ex) {
        // cannot convert to an URI, considering the location relative
        // unless it is the well-known Spring prefix "classpath*:"
    }

    // Absolute or relative?
    // 4. 绝对路径
    if (absoluteLocation) {
        try {
            // 添加配置文件地址的 Resource 到 actualResources 中,并加载相应的 BeanDefinition 们
            int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
            if (logger.isTraceEnabled()) {
                logger.trace("Imported " + importCount + " bean definitions from URL location [" + location + "]");
            }
        } catch (BeanDefinitionStoreException ex) {
            getReaderContext().error(
                    "Failed to import bean definitions from URL location [" + location + "]", ele, ex);
        }
    // 5. 相对路径
    } else {
        // No URL -> considering resource location as relative to the current file.
        try {
            int importCount;
            // 创建相对地址的 Resource
            Resource relativeResource = getReaderContext().getResource().createRelative(location);
            // 存在
            if (relativeResource.exists()) {
                // 加载 relativeResource 中的 BeanDefinition
                importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
                // 添加到 actualResources 中
                actualResources.add(relativeResource);
            // 不存在
            } else {
                // 获得根路径地址
                String baseLocation = getReaderContext().getResource().getURL().toString();
                // 添加配置文件地址的 Resource 到 actualResources 中,并加载相应的 BeanDefinition 们
                importCount = getReaderContext().getReader().loadBeanDefinitions(
                        StringUtils.applyRelativePath(baseLocation, location) /* 计算绝对路径 */, actualResources);
            }
            if (logger.isTraceEnabled()) {
                logger.trace("Imported " + importCount + " bean definitions from relative location [" + location + "]");
            }
        } catch (IOException ex) {
            getReaderContext().error("Failed to resolve current resource location", ele, ex);
        } catch (BeanDefinitionStoreException ex) {
            getReaderContext().error(
                    "Failed to import bean definitions from relative location [" + location + "]", ele, ex);
        }
    }
    // 6. 解析成功后,进行监听器激活处理
    Resource[] actResArray = actualResources.toArray(new Resource[0]);
    getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
  • 方法的调用流程。
    • 步骤 1,获取 source 属性的值,该值表示要导入的资源的路径。
    • 步骤 2,解析路径中的系统属性,如 " ${user.dir} " 。
    • 步骤 3,判断资源路径 location 是绝对路径还是相对路径。
    • 步骤 4,如果是 绝对路径,则递归调用 Bean 的解析过程,进行另一次的解析。
    • 步骤 5,如果是 相对路径,则先计算出绝对路径得到 Resource,然后进行解析。
    • 步骤 6,通知监听器,完成解析。

importBeanDefinitionResource 方法步骤 3 中的判断路径

absoluteLocation = ResourcePatternUtils.isUrl(location) // 1.
    || ResourceUtils.toURI(location).isAbsolute(); // 2.
  • 判断绝对路径的规则。
    • 步骤 1,以 classpath*: 或者 classpath: 开头的为绝对路径,或者能够通过该 location 构建出 java.net.URL 为绝对路径。
    • 步骤 2,根据 location 构造 java.net.URI 判断调用 isAbsolute() 方法,判断是否为绝对路径。

importBeanDefinitionResource 方法步骤 4 中的处理绝对路径

  • 如果 location 为绝对路径,则调用 loadBeanDefinitions() 方法。
    • 该方法在 org.springframework.beans.factory.support.AbstractBeanDefinitionReader 中定义。
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
    // 1. 获得 ResourceLoader 对象
    ResourceLoader resourceLoader = getResourceLoader();
    if (resourceLoader == null) {
        throw new BeanDefinitionStoreException(
                "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
    }

    if (resourceLoader instanceof ResourcePatternResolver) {
        // Resource pattern matching available.
        try {
            // 2. 获得 Resource 数组,因为 Pattern 模式匹配下,可能有多个 Resource 。例如说,Ant 风格的 location
            Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
            // 加载 BeanDefinition 们
            int count = loadBeanDefinitions(resources);
            // 添加到 actualResources 中
            if (actualResources != null) {
                Collections.addAll(actualResources, resources);
            }
            if (logger.isTraceEnabled()) {
                logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
            }
            return count;
        } catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "Could not resolve bean definition resource pattern [" + location + "]", ex);
        }
    } else {
        // Can only load single resources by absolute URL.
        // 获得 Resource 对象,
        Resource resource = resourceLoader.getResource(location);
        // 3. 加载 BeanDefinition
        int count = loadBeanDefinitions(resource);
        // 4. 添加到 actualResources 中
        if (actualResources != null) {
            actualResources.add(resource);
        }
        if (logger.isTraceEnabled()) {
            logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
        }
        return count;
    }
}
  • 方法的调用流程。
    • 步骤 1,获取 ResourceLoader 对象。
    • 步骤 2,根据不同的 ResourceLoader 执行不同的逻辑,主要是可能存在多个 Resource
    • 步骤 3,都会回归到 XmlBeanDefinitionReader#loadBeanDefinitions() 方法,这是一个 递归 的过程。
    • 步骤 4,获得到的 Resource 的对象或数组,都会添加到 actualResources 中。

importBeanDefinitionResource 步骤 5 中的处理相对路径

  • 如果 location 是相对路径,则会根据相应的 Resource 计算出相应的相对路径的 Resource 对象。
    • Resource 存在,则调用 XmlBeanDefinitionReader#loadBeanDefinitions() 方法,进行 BeanDefinition 加载。
    • 否则,构造一个绝对 location(即 StringUtils.applyRelativePath()),调用 loadBeanDefinitions() 方法,与 绝对路径 过程一样。

2.1.1.2 小结

  • 解析 import 标签的过程是,获取 source 属性值,得到正确的资源路径,然后调用 XmlBeanDefinitionReader#loadBeanDefinitions() 方法,进行递归的 BeanDefinition 加载。

2.1.2 解析 bean 标签

2.1.2.1 processBeanDefinition

// DefaultBeanDefinitionDocumentReader.java

/**
 * Process the given bean element, parsing the bean definition
 * and registering it with the registry.
 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 进行 bean 元素解析。
    // 1. 如果解析成功,则返回 BeanDefinitionHolder 对象。而 BeanDefinitionHolder 为 name 和 alias 的 BeanDefinition 对象
    // 如果解析失败,则返回 null 。
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        // 2. 进行自定义标签处理
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // 3. 进行 BeanDefinition 的注册
            // Register the final decorated instance.
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        } catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                    bdHolder.getBeanName() + "'", ele, ex);
        }
        // 4. 发出响应事件,通知相关的监听器,已完成该 Bean 标签的解析。
        // Send registration event.
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}
  • 方法的调用流程。
    • 步骤 1,进行元素解析。
      • 如果解析失败,则返回 null,错误由 ProblemReporter 处理。
      • 如果解析成功,则返回 BeanDefinitionHolder 实例 bdHolder 。BeanDefinitionHolder 为持有 name 和 alias 的 BeanDefinition
    • 步骤 2,若实例 bdHolder 不为空,则进行自定义标签处理。
    • 步骤 3,解析完成后,对 bdHolder 进行 BeanDefinition 的注册。
    • 步骤 4,发出响应事件,通知相关的监听器,完成 Bean 标签解析。

parseBeanDefinitionElement(Element, BeanDefinitionParserDelegate)

  • 进行 <bean> 元素的解析。
// BeanDefinitionParserDelegate.java

/**
 * Parses the supplied {@code <bean>} element. May return {@code null}
 * if there were errors during parse. Errors are reported to the
 * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
 */
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return parseBeanDefinitionElement(ele, null);
}

/**
 * Parses the supplied {@code <bean>} element. May return {@code null}
 * if there were errors during parse. Errors are reported to the
 * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
 *
 */
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    // 1.1 解析 id 和 name 属性
    String id = ele.getAttribute(ID_ATTRIBUTE);
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

    // 1.2 计算别名集合
    List<String> aliases = new ArrayList<>();
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        aliases.addAll(Arrays.asList(nameArr));
    }

    // 3.1 beanName ,优先,使用 id
    String beanName = id;
    // 3.2 beanName ,其次,使用 aliases 的第一个
    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");
        }
    }

    // 2. 检查 beanName 的唯一性
    if (containingBean == null) {
        checkNameUniqueness(beanName, aliases, ele);
    }

    // 4. 解析属性,构造 AbstractBeanDefinition 对象
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
        // 3.3 再次使用 beanName 生成规则
        if (!StringUtils.hasText(beanName)) {
            try {
                if (containingBean != null) {
                    // 3.3 生成唯一的 beanName
                    beanName = BeanDefinitionReaderUtils.generateBeanName(
                            beanDefinition, this.readerContext.getRegistry(), true);
                } else {
                    // 3.3 生成唯一的 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;
            }
        }
        // 5. 创建 BeanDefinitionHolder 对象
        String[] aliasesArray = StringUtils.toStringArray(aliases);
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }
    return null;
}

private final Set<String> usedNames = new HashSet<>();

/**
 * Validate that the specified bean name and aliases have not been used already
 * within the current level of beans element nesting.
 */
protected void checkNameUniqueness(String beanName, List<String> aliases, Element beanElement) {
    // 寻找是否 beanName 已经使用
    String foundName = null;
    if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) {
        foundName = beanName;
    }
    if (foundName == null) {
        foundName = CollectionUtils.findFirstMatch(this.usedNames, aliases);
    }
    // 若已使用,使用 problemReporter 提示错误
    if (foundName != null) {
        error("Bean name '" + foundName + "' is already used in this <beans> element", beanElement);
    }

    // 添加到 usedNames 集合
    this.usedNames.add(beanName);
    this.usedNames.addAll(aliases);
}
  • 方法的调用流程。
    • 步骤 1.1、1.2,解析 id、name 属性,确定 aliases 集合。
    • 步骤 2,检测 beanName 是否唯一。
    • 步骤 3.1,如果 id 不为空,则 beanName = id。
    • 步骤 3.2,如果 id 为空,但是 aliases 不空,则 beanName 为 aliases 的第一个元素。
    • 步骤 3.3,如果两者都为空,则根据默认规则来设置 beanName 。
    • 步骤 4,对属性进行解析并封装成 AbstractBeanDefinition 实例 beanDefinition
    • 步骤 5,根据所获取的信息(beanName、aliases、beanDefinition)构造 BeanDefinitionHolder 实例对象并返回。

parseBeanDefinitionElement(Element, String, BeanDefinition)

  • 对属性进行解析并封装成 AbstractBeanDefinition 实例。
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
        Element ele, String beanName, @Nullable BeanDefinition containingBean) {

    this.parseState.push(new BeanEntry(beanName));

    // 解析 class 属性
    String className = null;
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }
    // 解析 parent 属性
    String parent = null;
    if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
        parent = ele.getAttribute(PARENT_ATTRIBUTE);
    }

    try {
        // 创建用于承载属性的 AbstractBeanDefinition 实例
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);

        // 解析默认 bean 的各种属性(singleton,scope,abstract,lazy-init......)
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        // 提取 description
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

        // 以下是解析 <bean>......</bean> 内部的子元素,
        // 解析出来以后的信息都放到 bd 的属性中

        // 解析元数据 <meta />
        parseMetaElements(ele, bd);
        // 解析 lookup-method 属性 <lookup-method />
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        // 解析 replaced-method 属性 <replaced-method />
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

        // 解析构造函数参数 <constructor-arg />
        parseConstructorArgElements(ele, bd);
        // 解析 property 子元素 <property />
        parsePropertyElements(ele, bd);
        // 解析 qualifier 子元素 <qualifier />
        parseQualifierElements(ele, bd);

        bd.setResource(this.readerContext.getResource());
        bd.setSource(extractSource(ele));

        return bd;
    } catch (ClassNotFoundException ex) {
        error("Bean class [" + className + "] not found", ele, ex);
    } catch (NoClassDefFoundError err) {
        error("Class that bean class [" + className + "] depends on not found", ele, err);
    } catch (Throwable ex) {
        error("Unexpected failure during bean definition parsing", ele, ex);
    } finally {
        this.parseState.pop();
    }

    return null;
}
  • 解析得到一个基本可用的 BeanDefinition
2.1.2.1.1 BeanDefinition
  • org.springframework.beans.factory.config.BeanDefinition 是一个接口,描述了一个 Bean 实例的定义,包括属性值、构造方法值和继承自它的类的更多信息。
    • 解析 bean 标签的过程其实就是构造一个 BeanDefinition 对象的过程。
    • <bean> 元素标签拥有的配置属性,BeanDefinition 均提供了相应的属性,与之一一对应。
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;

void setParentName(@Nullable String parentName);
@Nullable
String getParentName();

void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();

void setScope(@Nullable String scope);
@Nullable
String getScope();

void setLazyInit(boolean lazyInit);
boolean isLazyInit();

void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();

void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();

void setPrimary(boolean primary);
boolean isPrimary();

void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();

void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();

ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
    return !getConstructorArgumentValues().isEmpty();
}

MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
    return !getPropertyValues().isEmpty();
}

void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();

void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();

void setRole(int role);
int getRole();

void setDescription(@Nullable String description);
@Nullable
String getDescription();

boolean isSingleton();

boolean isPrototype();

boolean isAbstract();

@Nullable
String getResourceDescription();

@Nullable
BeanDefinition getOriginatingBeanDefinition();

// AttributeAccessor.java
public interface AttributeAccessor {

    void setAttribute(String name, @Nullable Object value);

    @Nullable
    Object getAttribute(String name);

    @Nullable
    Object removeAttribute(String name);

    boolean hasAttribute(String name);

    String[] attributeNames();

}

// BeanMetadataElement.java
public interface BeanMetadataElement {

    @Nullable
    Object getSource();

}
2.1.2.1.1.1 BeanDefinition 的关系
  • BeanDefinition 继承 AttributeAccessorBeanMetadataElement 接口。
    • org.springframework.cor.AttributeAccessor 接口,定义了与其它对象的(元数据)进行连接和访问的约定,即对属性的修改,包括获取、设置、删除。
    • org.springframework.beans.BeanMetadataElement 接口,Bean 元对象持有的配置元素可以通过 getSource() 方法获取。
    • ChildBeanDefinitionRootBeanDefinitionGenericBeanDefinition 三者都继承 AbstractBeanDefinition 抽象类,即 AbstractBeanDefinition 对三个子类的共同的类信息进行抽象。
  • 配置文件中定义了父 <bean> 和 子 <bean>,父 <bean> 使用 RootBeanDefinition 表示,子 <bean> 使用 ChildBeanDefinition 表示,没有父 <bean> 使用 RootBeanDefinition 表示。
BeanDefinition 体系
2.1.2.1.2 createBeanDefinition
  • 创建 AbstractBeanDefinition 对象,委托 BeanDefinitionReaderUtils 创建。
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
        throws ClassNotFoundException {
    return BeanDefinitionReaderUtils.createBeanDefinition(
            parentName, className, this.readerContext.getBeanClassLoader());
}

// BeanDefinitionReaderUtils.java
public static AbstractBeanDefinition createBeanDefinition(
        @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
    // 创建 GenericBeanDefinition 对象
    GenericBeanDefinition bd = new GenericBeanDefinition();
    // 设置 parentName
    bd.setParentName(parentName);
    if (className != null) {
        // 设置 beanClass
        if (classLoader != null) {
            bd.setBeanClass(ClassUtils.forName(className, classLoader));
        // 设置 beanClassName
        } else {
            bd.setBeanClassName(className);
        }
    }
    return bd;
}
  • 创建 GenericBeanDefinition 对象,并设置 parentName、className、beanClass 属性。
2.1.2.1.3 parseBeanDefinitionAttributes
  • 将创建好的 GenericBeanDefinition 实例当做参数,对 bean 标签的所有属性进行解析。
// BeanDefinitionParserDelegate.java
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
        @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
    // 解析 scope 属性
    if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
        error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
    } else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
        bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
    } else if (containingBean != null) {
        // Take default from containing bean in case of an inner bean definition.
        bd.setScope(containingBean.getScope());
    }

    // 解析 abstract 属性
    if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
        bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
    }

    // 解析 lazy-init 属性
    String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
    if (DEFAULT_VALUE.equals(lazyInit)) {
        lazyInit = this.defaults.getLazyInit();
    }
    bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

    // 解析 autowire 属性
    String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
    bd.setAutowireMode(getAutowireMode(autowire));

    // 解析 depends-on 属性
    if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
        String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
        bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
    }

    // 解析 autowire-candidate 属性
    String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
    if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
        String candidatePattern = this.defaults.getAutowireCandidates();
        if (candidatePattern != null) {
            String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
            bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
        }
    } else {
        bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
    }

    // 解析 primary 标签
    if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
        bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
    }

    // 解析 init-method 属性
    if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
        String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
        bd.setInitMethodName(initMethodName);
    } else if (this.defaults.getInitMethod() != null) {
        bd.setInitMethodName(this.defaults.getInitMethod());
        bd.setEnforceInitMethod(false);
    }

    // 解析 destroy-method 属性
    if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
        String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
        bd.setDestroyMethodName(destroyMethodName);
    } else if (this.defaults.getDestroyMethod() != null) {
        bd.setDestroyMethodName(this.defaults.getDestroyMethod());
        bd.setEnforceDestroyMethod(false);
    }

    // 解析 factory-method 属性
    if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
        bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
    }
    if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
        bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
    }

    return bd;
}
属性 说明
scop 是否单例模式。
singleton:为单例模式,默认值;
prototype:为原型模式,多例模式。
abstract 是否为抽象类,默认值为 false,设为 true 不能被实例化。
lazy-init 是否延时加载,默认值为 false。设为 true 应用第一次用到 bean 时才实例化对象,否则在初始化 Spring 容器时加载单例 bean 对象。
autowire 配置 Spring 对象属性的默认的装配方式。
no:为不启用自动装配;
byType:为根据属性类型来找到和配置文件中配置的 class 类型一致的 bean 来自动装配,如果找到多个类型一致的 bean,则抛异常,如果一个都没有找到,则不执行装配操作,也不抛出异常;
byName:为根据名称自动装配,一般是 bean 的 name,如果不声明,默认值取的是 id;
default:(默认)为采用父级标签 beans 中的 default-autowire 属性;
constructor:为根据构造器中参数类型来自动装配,如果找到多个类型一致的 bean,则抛异常,如果一个都没有找到,则不执行装配操作,但是抛出异常(这是和 byType 不一样的地方)。
autodetect:Spring3 之前存在的值,通过 Bean 类的反省机制(introspection)决定是使用 constructor 还是使用 byType。
depends-on 作用是一个 bean 实例化的过程需要依赖于另一个 bean 的初始化,也就是说被依赖的 bean 将会在需要依赖的 bean 初始化之前加载。多个依赖 bean 之间用 " , " 号分割。
autowire-candidate 默认为 true,如果为 false,那么该 bean 不能作为其他 bean 自动装配的候选者。
primary 当一个 bean 出现多个候选者时,设置 为 true,则优先使用该 bean 自动装配。
init-method 作用是在创建一个 bean 之后调用该方法,初始化方法必须是一个无参方法。
destroy-method 作用是在销毁 bean 之前可以执行指定的方法。必须满足 scope = "singleton",并且 destroy 方法参数个数不能超过 1,并且参数只能为 boolean 类型。
factory-bean 将指定创建 bean 的工厂类对象(加载类),class 属性将失效。
factory-method 指定创建 bean 的工厂方法(加载静态方法)。
2.1.2.1.4 parseMetaElements
  • 解析 meta 子元素,元数据。
  • meta 所声明的 key 并不会在 Bean 中体现,只是一个额外的声明,当需要使用里面的信息时,通过调用 BeanDefinitiongetAttribute() 方法获取。
// BeanDefinitionParserDelegate.java
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
    NodeList nl = ele.getChildNodes();
    // 遍历子节点
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        // <meta key="special-data" value="sprecial stragey" />
        if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) { // 标签名为 meta
            Element metaElement = (Element) node;
            String key = metaElement.getAttribute(KEY_ATTRIBUTE); // key
            String value = metaElement.getAttribute(VALUE_ATTRIBUTE); // value
            // 创建 BeanMetadataAttribute 对象
            BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
            attribute.setSource(extractSource(metaElement));
            // 添加到 BeanMetadataAttributeAccessor 中
            attributeAccessor.addMetadataAttribute(attribute);
        }
    }
}
  • 获取相应的 key - value 构建 BeanMetadataAttribute 对象,加入到 AbstractBeanDefinition 中。

addMetadataAttribute

  • 调用 BeanMetadataAttributeAccessor#addMetadataAttribute() 方法,添加 BeanMetadataAttribute 加入到 AbstractBeanDefinition 中。
// BeanMetadataAttributeAccessor.java
public void addMetadataAttribute(BeanMetadataAttribute attribute) {
    super.setAttribute(attribute.getName(), attribute);
}
  • 委托 AttributeAccessorSupport 实现。
    • org.springframework.core.AttributeAccessorSupport 是接口 AttributeAccessor 的实现。AttributeAccessor 接口定义了与其他对象的元数据进行连接和访问的约定,可以通过该接口对属性进行获取、设置、删除操作。
// AttributeAccessorSupport.java
/** Map with String keys and Object values. */
private final Map<String, Object> attributes = new LinkedHashMap<>();

@Override
public void setAttribute(String name, @Nullable Object value) {
    Assert.notNull(name, "Name must not be null");
    if (value != null) {
        this.attributes.put(name, value);
    } else {
        removeAttribute(name);
    }
}

getAttribute

  • 设置元数据后,则可以通过调用 BeanDefinitiongetAttribute() 方法获取属性。
// AttributeAccessorSupport.java
/** Map with String keys and Object values. */
private final Map<String, Object> attributes = new LinkedHashMap<>();

@Override
@Nullable
public Object getAttribute(String name) {
    Assert.notNull(name, "Name must not be null");
    return this.attributes.get(name);
}
2.1.2.1.5 parseLookupOverrideSubElements
  • 获取器(lookup-method)的注入,是把一个方法声明为返回某种类型的 bean,但实际要返回的 bean 可以在配置文件中配置。
    • 该方法可以用于设计一些可插拔的功能上,解除程序依赖,用例如下。
public interface Color {
    void display();
}

public class Blue implements Color {
    @Override
    public void display() {
        System.out.println("blue");
    }
}

public class Red implements Color {
    @Override
    public void display() {
        System.out.println("red");
    }
}

public abstract class Display {
    public void display(){
        getColor().display();
    }
    public abstract Color getColor();
}

public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
    Display display = (Display) context.getBean("display");
    display.display();
}

/**
输出:red
如果将 bean="red" 替换为 bean="blue"
输出:blue
**/

//spring.xml
<bean id="display" class="org.springframework.core.test.Display">
    <lookup-method name="getColor" bean="red"/>
</bean>
  • 解析 methodName、beanRef 构造一个 LookupOverride 对象,记录到 AbstractBeanDefinition 的 methodOverrides 属性中。
// BeanDefinitionParserDelegate.java
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
    NodeList nl = beanEle.getChildNodes();
    // 遍历子节点
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) { // 标签名为 lookup-method
            Element ele = (Element) node;
            String methodName = ele.getAttribute(NAME_ATTRIBUTE); // name
            String beanRef = ele.getAttribute(BEAN_ELEMENT); // bean
            // 创建 LookupOverride 对象
            LookupOverride override = new LookupOverride(methodName, beanRef);
            override.setSource(extractSource(ele));
            // 添加到 MethodOverrides 中
            overrides.addOverride(override);
        }
    }
}
2.1.2.1.6 parseReplacedMethodSubElements
  • replaced-method 可以在运行时调用新的方法替换现有的方法,还能动态的更新原有方法的逻辑。
    • 需要实现 org.springframework.beans.factory.support.MethodReplacer 接口,用例如下。
public class Method {
    public void display(){
        System.out.println("origin");
    }
}

public class MethodReplace implements MethodReplacer {

    @Override
    public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
        System.out.println("replace");
        return null;
    }

}

public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
    Method method = (Method) context.getBean("method");
    method.display();
}

/**
输出:replace
**/

//spring.xml
<bean id="methodReplace" class="org.springframework.core.test.MethodReplace"/>
<bean id="method" class="org.springframework.core.test.Method">
    <replaced-method name="display" replacer="methodReplace"/>
</bean>
  • 提取 name 和 replacer 属性构建 ReplaceOverride 对象,然后记录到 AbstractBeanDefinition 中的 methodOverrides 属性中。
/**
 * Parse replaced-method sub-elements of the given bean element.
 */
public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
    NodeList nl = beanEle.getChildNodes();
    // 遍历子节点
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) { // 标签名为 replace-method
            Element replacedMethodEle = (Element) node;
            String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE); // name
            String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE); // replacer
            // 创建 ReplaceOverride 对象
            ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
            List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT); // arg-type 子标签
            for (Element argTypeEle : argTypeEles) {
                String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE); // arg-type 子标签的 match 属性
                match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle));
                if (StringUtils.hasText(match)) {
                    replaceOverride.addTypeIdentifier(match);
                }
            }
            replaceOverride.setSource(extractSource(replacedMethodEle));
            // 添加到 MethodOverrides 中
            overrides.addOverride(replaceOverride);
        }
    }
}
2.1.2.1.7 parseConstructorArgElements
  • 配置文件中使用 constructor-arg 元素对其配置,该元素可以实现自动寻找对应的构造函数,并在初始化时将值当做参数进行设置,用例如下。
public class StudentService {
    private String name;
    private Integer age;
    private BookService bookService;
    StudentService(String name, Integer age, BookService bookService){
        this.name = name;
        this.age = age;
        this.bookService = bookService;
    }
}

//spring.xml
<bean id="bookService" class="org.springframework.core.service.BookService"/>
<bean id="studentService" class="org.springframework.core.service.StudentService">
    <constructor-arg index="0" value="wang"/>
    <constructor-arg name="age" value="18"/>
    <constructor-arg name="bookService" ref="bookService"/>
</bean>
  • 遍历所有子元素,如果为 constructor-arg 标签,则调用 parseConstructorArgElement(Element, BeanDefinition) 方法解析。
// BeanDefinitionParserDelegate.java
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) { // 标签名为 constructor-arg
            parseConstructorArgElement((Element) node, bd);
        }
    }
}

parseConstructorArgElement

// BeanDefinitionParserDelegate.java
public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
    // 提取 index、type、name 属性值
    String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
    String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    if (StringUtils.hasLength(indexAttr)) {
        try {
            // 如果有 index
            int index = Integer.parseInt(indexAttr);
            if (index < 0) {
                error("'index' cannot be lower than 0", ele);
            } else {
                try {
                    // 1.
                    this.parseState.push(new ConstructorArgumentEntry(index));
                    // 2. 解析 ele 对应属性元素
                    Object value = parsePropertyValue(ele, bd, null);
                    // 3. 根据解析的属性元素构造一个 ValueHolder 对象
                    ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
                    if (StringUtils.hasLength(typeAttr)) {
                        valueHolder.setType(typeAttr);
                    }
                    if (StringUtils.hasLength(nameAttr)) {
                        valueHolder.setName(nameAttr);
                    }
                    valueHolder.setSource(extractSource(ele));
                    // 不允许重复指定相同参数
                    if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
                        error("Ambiguous constructor-arg entries for index " + index, ele);
                    } else {
                        // 4. 加入到 indexedArgumentValues 中
                        bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
                    }
                } finally {
                    this.parseState.pop();
                }
            }
        } catch (NumberFormatException ex) {
            error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
        }
    } else {
        try {
            this.parseState.push(new ConstructorArgumentEntry());
            // 解析 ele 对应属性元素
            Object value = parsePropertyValue(ele, bd, null);
            // 根据解析的属性元素构造一个 ValueHolder 对象
            ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
            if (StringUtils.hasLength(typeAttr)) {
                valueHolder.setType(typeAttr);
            }
            if (StringUtils.hasLength(nameAttr)) {
                valueHolder.setName(nameAttr);
            }
            valueHolder.setSource(extractSource(ele));
            // 加入到 indexedArgumentValues 中
            bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
        } finally {
            this.parseState.pop();
        }
    }
}
  • 首先获取 index、type、name 三个属性值,然后根据是否存在 index 来区分(有无 index 逻辑类似),执行后续逻辑。
  • 方法的调用流程。
    • 步骤 1,构造 ConstructorArgumentEntry 对象并将其加入到 ParseState 队列中。ConstructorArgumentEntry 表示构造函数的参数。
    • 步骤 2,解析 constructor-arg 子元素,返回结果值。
    • 步骤 3,根据解析的结果值,构造 ConstructorArgumentValues.ValueHolder 实例对象,并将 type、name 设置到 ValueHolder 中。
    • 步骤 4,将 ValueHolder 实例对象添加到 indexedArgumentValues 集合中。
  • 无 index 的处理逻辑类似,区别在于。
    • 构造 ConstructorArgumentEntry 对象时调用无参构造函数。
    • 最后将 ValueHolder 实例添加到 genericArgumentValues 集合中。

parsePropertyValue

  • 解析 constructor-arg 子元素,返回结果值。
@Nullable
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
    String elementName = (propertyName != null ?
            "<property> element for property '" + propertyName + "'" :
            "<constructor-arg> element");

    // 1. 查找子节点中,是否有 ref、value、list 等元素
    // Should only have one child element: ref, value, list, etc.
    NodeList nl = ele.getChildNodes();
    Element subElement = null;
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        // meta 、description 不处理
        if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
                !nodeNameEquals(node, META_ELEMENT)) {
            // Child element is what we're looking for.
            if (subElement != null) {
                error(elementName + " must not contain more than one sub-element", ele);
            } else {
                subElement = (Element) node;
            }
        }
    }

    // 1.1. 是否有 ref 属性
    boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
    // 1.2. 是否有 value 属性
    boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
    // 1.3. 多个元素存在,报错,存在冲突。
    if ((hasRefAttribute && hasValueAttribute) || // 1. ref 和 value 都存在
            ((hasRefAttribute || hasValueAttribute) && subElement != null)) { // 2. ref he value 存在一,并且 subElement 存在
        error(elementName +
                " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
    }

    // 2. 将 ref 属性值,构造为 RuntimeBeanReference 实例对象
    if (hasRefAttribute) {
        String refName = ele.getAttribute(REF_ATTRIBUTE);
        if (!StringUtils.hasText(refName)) {
            error(elementName + " contains empty 'ref' attribute", ele);
        }
        RuntimeBeanReference ref = new RuntimeBeanReference(refName);
        ref.setSource(extractSource(ele));
        return ref;
    // 3. 将 value 属性值,构造为 TypedStringValue 实例对象
    } else if (hasValueAttribute) {
        TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
        valueHolder.setSource(extractSource(ele));
        return valueHolder;
    // 4. 解析子元素
    } else if (subElement != null) {
        return parsePropertySubElement(subElement, bd);
    } else {
        // Neither child element nor "ref" or "value" attribute found.
        error(elementName + " must specify a ref or value", ele);
        return null;
    }
}
  • 方法的调用流程。
    • 步骤 1,提取 constructor-arg 的子元素、ref 属性值和 value 属性值,对其进行判断。
      • ref 和 value 属性同时存在 。
      • 存在 ref 或者 value 且又有子元素。
    • 步骤 2,若存在 ref 属性,则获取其值并将其封装进 RuntimeBeanReference 实例对象中。
    • 步骤 3,若存在 value 属性,则获取其值并将其封装进 TypedStringValue 实例对象中。
    • 步骤 4,如果子元素不为空,则调用 parsePropertySubElement() 方法,对子元素进一步解析。

parsePropertySubElement

  • 对于 constructor-arg 子元素的嵌套子元素进一步处理。
@Nullable
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
    if (!isDefaultNamespace(ele)) {
        return parseNestedCustomElement(ele, bd);
    } else if (nodeNameEquals(ele, BEAN_ELEMENT)) { // bean 标签
        BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
        if (nestedBd != null) {
            nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
        }
        return nestedBd;
    } else if (nodeNameEquals(ele, REF_ELEMENT)) { // ref 标签
        // A generic reference to any name of any bean.
        String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
        boolean toParent = false;
        if (!StringUtils.hasLength(refName)) {
            // A reference to the id of another bean in a parent context.
            refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
            toParent = true;
            if (!StringUtils.hasLength(refName)) {
                error("'bean' or 'parent' is required for <ref> element", ele);
                return null;
            }
        }
        if (!StringUtils.hasText(refName)) {
            error("<ref> element contains empty target attribute", ele);
            return null;
        }
        RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
        ref.setSource(extractSource(ele));
        return ref;
    } else if (nodeNameEquals(ele, IDREF_ELEMENT)) { // idref 标签
        return parseIdRefElement(ele);
    } else if (nodeNameEquals(ele, VALUE_ELEMENT)) { // value 标签
        return parseValueElement(ele, defaultValueType);
    } else if (nodeNameEquals(ele, NULL_ELEMENT)) { // null 标签
        // It's a distinguished null value. Let's wrap it in a TypedStringValue
        // object in order to preserve the source location.
        TypedStringValue nullHolder = new TypedStringValue(null);
        nullHolder.setSource(extractSource(ele));
        return nullHolder;
    } else if (nodeNameEquals(ele, ARRAY_ELEMENT)) { // array 标签
        return parseArrayElement(ele, bd);
    } else if (nodeNameEquals(ele, LIST_ELEMENT)) { // list 标签
        return parseListElement(ele, bd);
    } else if (nodeNameEquals(ele, SET_ELEMENT)) { // set 标签
        return parseSetElement(ele, bd);
    } else if (nodeNameEquals(ele, MAP_ELEMENT)) { // map 标签
        return parseMapElement(ele, bd);
    } else if (nodeNameEquals(ele, PROPS_ELEMENT)) { // props 标签
        return parsePropsElement(ele);
    } else { // 未知标签
        error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
        return null;
    }
}
2.1.2.1.8 parsePropertyElements
  • 配置文件中使用 property 元素配置对象属性,用例如下。
<bean id="studentService" class="org.springframework.core.service.StudentService">
    <property name="name" value="wang"/>
    <property name="age" value="18"/>
</bean>
  • Spring 调用 parsePropertyElements() 方法,对 property 子元素进行解析。
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { // property 标签
            parsePropertyElement((Element) node, bd);
        }
    }
}

parsePropertyElement

  • 同样遍历所有的 property 元素,调用 parsePropertyElement() 进行解析。
public void parsePropertyElement(Element ele, BeanDefinition bd) {
    // 获取 name 属性
    String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
    if (!StringUtils.hasLength(propertyName)) {
        error("Tag 'property' must have a 'name' attribute", ele);
        return;
    }
    this.parseState.push(new PropertyEntry(propertyName));
    try {
        // 如果存在相同的 name ,报错
        if (bd.getPropertyValues().contains(propertyName)) {
            error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
            return;
        }
        // 1. 解析属性值
        Object val = parsePropertyValue(ele, bd, propertyName);
        // 2. 创建 PropertyValue 对象
        PropertyValue pv = new PropertyValue(propertyName, val);
        parseMetaElements(ele, pv);
        pv.setSource(extractSource(ele));
        // 3. 添加到 PropertyValue 集合中
        bd.getPropertyValues().addPropertyValue(pv);
    } finally {
        this.parseState.pop();
    }
}
  • 方法的调用流程。
    • 步骤 1, 解析子元素属性值。
    • 步骤 2,根据该值构造 PropertyValue 实例对象。
    • 步骤 3,将 PropertyValue 添加到 BeanDefinition 中的 MutablePropertyValues 中。
2.1.2.1.9 parseQualifierElements
  • 完成 qualifier 子元素的解析。
public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
    // 解析 type 属性
    String typeName = ele.getAttribute(TYPE_ATTRIBUTE);
    if (!StringUtils.hasLength(typeName)) { // 必须有 type
        error("Tag 'qualifier' must have a 'type' attribute", ele);
        return;
    }
    this.parseState.push(new QualifierEntry(typeName));
    try {
        // 创建 AutowireCandidateQualifier 对象
        AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);
        qualifier.setSource(extractSource(ele));
        // 解析 value 属性,并设置到 AutowireCandidateQualifier 中
        String value = ele.getAttribute(VALUE_ATTRIBUTE);
        if (StringUtils.hasLength(value)) {
            qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value);
        }
        // 遍历子节点
        NodeList nl = ele.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) { // attribute 标签
                Element attributeEle = (Element) node;
                String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE); // attribute 标签的 key 属性
                String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE); // attribute 标签的 value 属性
                if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) {
                    // 创建 BeanMetadataAttribute 对象
                    BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
                    attribute.setSource(extractSource(attributeEle));
                    // 添加到 attributes 中
                    qualifier.addMetadataAttribute(attribute);
                } else {
                    error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
                    return;
                }
            }
        }
        // 添加到 qualifiers 中
        bd.addQualifier(qualifier);
    } finally {
        this.parseState.pop();
    }
}
  • 用例如下。
<qualifier type="org.springframework.beans.factory.annotation.Qualifier" value="限定标识符"/> 
  • 其中 type 属性可选,指定类型,默认是 Qualifier 注解类,value 是 Bean 的候选者指定限定标识符,一个 Bean 定义中只允许指定类型不同的 <qualifier>,如果有多个相同 type 后面指定的将覆盖前面的。

2.1.2.2 decorateBeanDefinitionIfRequired

  • 在 <2.1.2.1> 解析过程中,首先调用 parseBeanDefinitionElement() 方法,完成默认标签的解析,如果解析成功(返回的 bdHolder != null),则调用 decorateBeanDefinitionIfRequired() 方法完成 自定义标签元素 的解析。
// BeanDefinitionParserDelegate.java
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
        Element ele, BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) {

    BeanDefinitionHolder finalDefinition = definitionHolder;

    // 1. 遍历属性,查看是否有适用于装饰的【属性】
    // Decorate based on custom attributes first.
    NamedNodeMap attributes = ele.getAttributes();
    for (int i = 0; i < attributes.getLength(); i++) {
        Node node = attributes.item(i);
        finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
    }

    // 2. 遍历子节点,查看是否有适用于修饰的【子节点】
    // Decorate based on custom nested elements.
    NodeList children = ele.getChildNodes();
    for (int i = 0; i < children.getLength(); i++) {
        Node node = children.item(i);
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
        }
    }
    return finalDefinition;
}
  • 方法的调用流程。
    • 步骤 1,遍历属性(attributes)。
    • 步骤 2,遍历子节点(childNodes)。
  • 最终都调用 decorateIfRequired() 方法,装饰对应的节点(Node)。

decorateIfRequired

// BeanDefinitionParserDelegate.java
public BeanDefinitionHolder decorateIfRequired(
        Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
    // 1. 获取自定义标签的命名空间
    String namespaceUri = getNamespaceURI(node);
    // 2. 过滤掉默认命名标签
    if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
        // 2. 获取相应的处理器
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler != null) {
            // 3. 进行装饰处理
            BeanDefinitionHolder decorated =
                    handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
            if (decorated != null) {
                return decorated;
            }
        } else if (namespaceUri.startsWith("http://www.springframework.org/")) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
        } else {
            // A custom namespace, not to be handled by Spring - maybe "xml:...".
            if (logger.isDebugEnabled()) {
                logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
            }
        }
    }
    return originalDef;
}
  • 方法的调用流程。
    • 步骤 1,首先获取自定义标签的命名空间。
    • 步骤 2,如果不是 默认的命名空间,则根据该命名空间获取相应的处理器。
    • 步骤 3,如果处理器存在,则进行装饰处理。

2.2 自定义标签

  • 例如:<tx:annotation-driven>

2.2.1 使用自定义标签

  • 扩展 Spring 自定义标签配置一般需要以下步骤。
    • 步骤 1,创建一个需要扩展的组件(Bean)。
    • 步骤 2,定义一个 XSD 文件,用于描述组件内容。
    • 步骤 3,创建一个实现 org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser 接口的类,用于解析 XSD 文件中的定义和组件定义。
    • 步骤 4,创建一个 Handler,继承 org.springframework.beans.factory.xml.NamespaceHandlerSupport 抽象类 ,用于将组件注册到 Spring 容器。
    • 步骤 5,编写 spring.handlers 和 Spring.schemas 文件。

创建组件

  • 创建一个普通的 Java Bean。
public class User {
    private String id;
    private String userName;
    private String email;
}

定义 XSD 文件

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.test.com/schema/user" targetNamespace="http://www.test.com/schema/user" elementFormDefault="qualified">
    <xsd:element name="user">
        <xsd:complexType>
            <xsd:attribute name="id" type="xsd:string" />
            <xsd:attribute name="userName" type="xsd:string" />
            <xsd:attribute name="email" type="xsd:string" />
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

定义 Parser 类

  • 定义一个 Parser 类,继承 AbstractSingleBeanDefinitionParser,并实现 getBeanClass()doParse() 两个方法。
    • 主要用于解析 XSD 文件中的定义和组件定义。
public class UserDefinitionParser extends AbstractSingleBeanDefinitionParser {

    @Override
    protected Class<?> getBeanClass(Element element) {
        return User.class;
    }

    @Override
    protected void doParse(Element element, BeanDefinitionBuilder builder) {
        String id = element.getAttribute("id");
        String userName = element.getAttribute("userName");
        String email = element.getAttribute("email");

        if (StringUtils.hasText(id)) {
            builder.addPropertyValue("id", id);
        }

        if (StringUtils.hasText(userName)) {
            builder.addPropertyValue("userName", userName);
        }

        if (StringUtils.hasText(email)) {
            builder.addPropertyValue("email", email);
        }
    }

}

定义 NamespaceHandler 类

  • 定义 NamespaceHandler 类,继承 NamespaceHandlerSupport,将组件注册到 Spring 容器中。
public class UserNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("user", new UserDefinitionParser());
    }
}

定义 spring.handlers 文件

http\://www.test.com/schema/user=org.springframework.core.customelement.UserNamespaceHandler

定义 Spring.schemas 文件

http\://www.test.com/schema/user.xsd=user.xsd

运行

  • 在 XML 配置文件中使用。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:myTag="http://www.test.com/schema/user"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.test.com/schema/user http://www.test.com/schema/user.xsd">
    <myTag:user id="user" email="test@163.com" userName="wang" />
</beans>

public static void main(String[] args){
    ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
    User user = (User) context.getBean("user");
    System.out.println(user.getId() + "----" + user.getUserName() + "----" + user.getEmail());
}

/**print
user----wang----test@163.com
**/

2.2.2 解析自定义标签

  • 解析自定义标签BeanDefinitionParserDelegateparseCustomElement() 方法实现。

parseCustomElement

@Nullable
public BeanDefinition parseCustomElement(Element ele) {
    return parseCustomElement(ele, null);
}

@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
    // 1. 获取 namespaceUri
    String namespaceUri = getNamespaceURI(ele);
    if (namespaceUri == null) {
        return null;
    }
    // 2. 根据 namespaceUri 获取相应的 Handler
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
        return null;
    }
    // 3. 调用自定义的 Handler 处理
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

@Nullable
public String getNamespaceURI(Node node) {
    return node.getNamespaceURI();
}
  • 方法的调用流程。
    • 步骤 1,调用 getNamespaceURI() 方法,获取 namespaceUri
    • 步骤 2,调用 XmlReaderContext#getNamespaceHandlerResolver(),获得命名空间的解析器。
      • 根据 namespaceUri 获取相应的 Handler 对象。这个映射关系在 spring.handlers 中定义,只需要查找到该类,进行初始化返回。
    • 步骤 3,调用 NamespaceHandler#parse() 自定义的 Handler 处理。

2.2.2.1 getNamespaceHandlerResolver

  • 调用 XmlReaderContextgetNamespaceHandlerResolver() 方法,返回的命名空间的解析器。
/**
 * NamespaceHandler 解析器
 */
private final NamespaceHandlerResolver namespaceHandlerResolver;
public final NamespaceHandlerResolver getNamespaceHandlerResolver() {
    return this.namespaceHandlerResolver;
}
2.2.2.1.1 NamespaceHandlerResolver 的初始化
// XmlBeanDefinitionReader.java
public XmlReaderContext createReaderContext(Resource resource) {
    return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
            this.sourceExtractor, this, getNamespaceHandlerResolver());
}

getNamespaceHandlerResolver

// XmlBeanDefinitionReader.java
public NamespaceHandlerResolver getNamespaceHandlerResolver() {
    if (this.namespaceHandlerResolver == null) {
        this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
    }
    return this.namespaceHandlerResolver;
}

protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
    ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader());
    return new DefaultNamespaceHandlerResolver(cl); 
}
  • NamespaceHandlerResolver 对象的最终类型是 org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver

2.2.2.2 resolve

@Override
@Nullable
public NamespaceHandler resolve(String namespaceUri) {
    // 1. 获取所有已经配置的 Handler 映射
    Map<String, Object> handlerMappings = getHandlerMappings();
    // 2. 根据 namespaceUri 获取 handler 的信息
    Object handlerOrClassName = handlerMappings.get(namespaceUri);
    // 3.1. 不存在
    if (handlerOrClassName == null) {
        return null;
    // 3.2. 已经初始化
    } else if (handlerOrClassName instanceof NamespaceHandler) {
        return (NamespaceHandler) handlerOrClassName;
    // 3.3. 需要进行初始化
    } else {
        String className = (String) handlerOrClassName;
        try {
            // 获得类,并创建 NamespaceHandler 对象
            Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
            if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                        "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
            }
            NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
            // 初始化 NamespaceHandler 对象
            namespaceHandler.init();
            // 添加到缓存
            handlerMappings.put(namespaceUri, namespaceHandler);
            return namespaceHandler;
        } catch (ClassNotFoundException ex) {
            throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
                    "] for namespace [" + namespaceUri + "]", ex);
        } catch (LinkageError err) {
            throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
                    className + "] for namespace [" + namespaceUri + "]", err);
        }
    }
}
  • 方法的调用流程。
    • 步骤 1,调用 getHandlerMappings() 方法,获取所有配置文件中的映射关系 handlerMappings 。
    • 步骤 2,根据 namespaceUri 获取 handler 的信息。
    • 步骤 3.1,如果 handlerOrClassName 不存在,则返回 null 空。
    • 步骤 3.2,如果 handlerOrClassName 已经初始化成 NamespaceHandler 对象,直接返回。
    • 步骤 3.3,如果 handlerOrClassName 还是类路径,则创建 NamespaceHandler 对象,并调用 NamespaceHandler#init() 方法,初始化 NamespaceHandler 对象。
      • 创建的 NamespaceHandler 对象,会添加到 handlerMappings 中,进行缓存。

getHandlerMappings

  • 通过延迟加载(lazy-init)方式,加载 handlerMappingsLocation 中配置的 NamespaceHandler 的映射,到 handlerMappings 中。
  • andlerMappings 的值属性有 2 种情况。
    • 未初始化时,对应的 NamespaceHandler 的类路径。
    • 已初始化时,对应的 NamespaceHandler 对象。
/** ClassLoader to use for NamespaceHandler classes. */
@Nullable
private final ClassLoader classLoader;

/**
 * NamespaceHandler 映射配置文件地址
 *
 * Resource location to search for.
 */
private final String handlerMappingsLocation;

/**
 * Stores the mappings from namespace URI to NamespaceHandler class name / instance.
 *
 * NamespaceHandler 映射。
 *
 * key:命名空间
 * value:分成两种情况
 */
@Nullable
private volatile Map<String, Object> handlerMappings;

/**
 * Load the specified NamespaceHandler mappings lazily.
 */
private Map<String, Object> getHandlerMappings() {
    // 双重检查锁,延迟加载
    Map<String, Object> handlerMappings = this.handlerMappings;
    if (handlerMappings == null) {
        synchronized (this) {
            handlerMappings = this.handlerMappings;
            if (handlerMappings == null) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
                }
                try {
                    // 读取 handlerMappingsLocation
                    Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                    if (logger.isTraceEnabled()) {
                        logger.trace("Loaded NamespaceHandler mappings: " + mappings);
                    }
                    // 初始化到 handlerMappings 中
                    handlerMappings = new ConcurrentHashMap<>(mappings.size());
                    CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
                    this.handlerMappings = handlerMappings;
                } catch (IOException ex) {
                    throw new IllegalStateException(
                            "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
                }
            }
        }
    }
    return handlerMappings;
}

init

  • 假设还是使用之前 <2.2.1> 中的定义 NamespaceHandler 类,将自定义标签解析器进行注册。
// UserNamespaceHandler.java
public class UserNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("user", new UserDefinitionParser());
    }
}
  • 调用父类 NamespaceHandlerSupportregisterBeanDefinitionParser() 方法,注册指定元素的 BeanDefinitionParser 解析器。

registerBeanDefinitionParser

  • 注册指定元素的 BeanDefinitionParser 解析器。
    • 将映射关系放在一个 Map 结构的 parsers 对象中。
// NamespaceHandlerSupport.java
/**
 * Stores the {@link BeanDefinitionParser} implementations keyed by the
 * local name of the {@link Element Elements} they handle.
 *
 * key:元素名
 * value:对应 BeanDefinitionParser 的解析器
 */
private final Map<String, BeanDefinitionParser> parsers = new HashMap<>();

protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
    this.parsers.put(elementName, parser);
}

2.2.2.3 parse

  • 开始自定义标签的解析。
// NamespaceHandlerSupport.java
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
    // 1. 获得元素对应的 BeanDefinitionParser 对象
    BeanDefinitionParser parser = findParserForElement(element, parserContext);
    // 2. 执行解析
    return (parser != null ? parser.parse(element, parserContext) : null);
}

@Nullable
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
    // 获得元素名
    String localName = parserContext.getDelegate().getLocalName(element);
    // 获得 BeanDefinitionParser 对象
    BeanDefinitionParser parser = this.parsers.get(localName);
    if (parser == null) {
        parserContext.getReaderContext().fatal(
                "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
    }
    return parser;
}
  • 方法的调用流程。
    • 步骤 1,获取对应的 BeanDefinitionParser 实例。实际上是获取在 NamespaceHandlerSupportregisterBeanDefinitionParser() 方法里面注册的实例对象。
      • 获取 localName(上例中为 user)。
      • 从 Map 实例 parsers 中获取 BeanDefinitionParser 对象(上例中为UserBeanDefinitionParser 对象)。
    • 步骤 2,返回 BeanDefinitionParser 对象后,调用其 parse() 方法。该方法在 AbstractBeanDefinitionParser 中实现。
// AbstractBeanDefinitionParser.java
@Override
@Nullable
public final BeanDefinition parse(Element element, ParserContext parserContext) {
    // 内部解析,返回 AbstractBeanDefinition 对象
    AbstractBeanDefinition definition = parseInternal(element, parserContext);
    if (definition != null && !parserContext.isNested()) {
        try {
            // 解析 id 属性
            String id = resolveId(element, definition, parserContext);
            if (!StringUtils.hasText(id)) {
                parserContext.getReaderContext().error(
                        "Id is required for element '" + parserContext.getDelegate().getLocalName(element)
                                + "' when used as a top-level tag", element);
            }
            // 解析 aliases 属性
            String[] aliases = null;
            if (shouldParseNameAsAliases()) {
                String name = element.getAttribute(NAME_ATTRIBUTE);
                if (StringUtils.hasLength(name)) {
                    aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
                }
            }
            // 创建 BeanDefinitionHolder 对象
            BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
            // 注册 BeanDefinition
            registerBeanDefinition(holder, parserContext.getRegistry());
            // 触发事件
            if (shouldFireEvents()) {
                BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
                postProcessComponentDefinition(componentDefinition);
                parserContext.registerComponent(componentDefinition);
            }
        } catch (BeanDefinitionStoreException ex) {
            String msg = ex.getMessage();
            parserContext.getReaderContext().error((msg != null ? msg : ex.toString()), element);
            return null;
        }
    }
    return definition;
}

parseInternal

  • 解析 XML 元素为 AbstractBeanDefinition 对象。
// AbstractSingleBeanDefinitionParser.java
@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
    // 创建 BeanDefinitionBuilder 对象
    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
    // 获取父类元素
    String parentName = getParentName(element);
    if (parentName != null) {
        builder.getRawBeanDefinition().setParentName(parentName);
    }
    // 获取自定义标签中的 class,这个时候会去调用自定义解析中的 getBeanClass()
    Class<?> beanClass = getBeanClass(element);
    if (beanClass != null) {
        builder.getRawBeanDefinition().setBeanClass(beanClass);
    } else {
        // beanClass 为 null,意味着子类并没有重写 getBeanClass() 方法,则尝试去判断是否重写了 getBeanClassName()
        String beanClassName = getBeanClassName(element);
        if (beanClassName != null) {
            builder.getRawBeanDefinition().setBeanClassName(beanClassName);
        }
    }
    // 设置 source 属性
    builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
    // 设置 scope 属性
    BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
    if (containingBd != null) {
        // Inner bean definition must receive same scope as containing bean.
        builder.setScope(containingBd.getScope());
    }
    // 设置 lazy-init 属性
    if (parserContext.isDefaultLazyInit()) {
        // Default-lazy-init applies to custom bean definitions as well.
        builder.setLazyInit(true);
    }
    // 调用子类的 doParse() 进行解析
    doParse(element, parserContext, builder);
    return builder.getBeanDefinition();
}

2.2.3 小结

  • 自定义标签的解析的整个过程。
    • 加载 spring.handlers 文件,将其中内容进行一个解析,形成 <namespaceUri, 类路径> 这样的一个映射。
    • 根据获取的 namespaceUri 可以得到相应的类路径,对其进行初始化,得到相应的 NamespaceHandler 对象。
    • 调用该 NamespaceHandlerparse() 方法,根据标签的 localName 得到相应的 BeanDefinitionParser 实例对象。
    • 调用该 BeanDefinitionParser 的 parse()` 方法。
      • 方法定义在 AbstractBeanDefinitionParser 抽象类中,核心逻辑封装在其 parseInternal() 方法中,该方法返回一个 AbstractBeanDefinition 实例对象,其主要是在 AbstractSingleBeanDefinitionParser 中实现。
      • 对于自定义的 Parser 类,需要实现 getBeanClass() 或者 getBeanClassName() 任一方法,和 doParse() 方法。

相关文章

网友评论

    本文标题:【Spring 笔记】Bean 解析相关整理

    本文链接:https://www.haomeiwen.com/subject/zwequctx.html