Spring IoC源码学习:parseDefaultElement 详解

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 接着 Spring IoC:obtainFreshBeanFactory详解 继续往下解析,本文来到 parseDefaultElement 方法。该方法是解析默认命名空间节点的方法,是加载 bean 定义模块的最核心方法。

目录

Spring IoC源码学习全系列

前言

正文

parseDefaultElement

processBeanDefinition

代码块1parseBeanDefinitionElement

代码块2parseBeanDefinitionElement

代码块3parseBeanDefinitionAttributes

代码块4parseConstructorArgElements

代码块5parseConstructorArgElement

代码块6parsePropertyValue

代码块7parsePropertySubElement

代码块8parseValueElement

代码块9buildTypedStringValue

代码块10parseListElement

代码块11parsePropertyElements

代码块12parsePropertyElement

代码块13registerBeanDefinition

代码块14registerBeanDefinition

代码块15resetBeanDefinition

代码块16registerAlias

总结

相关文章


Spring IoC源码学习全系列

小白也看得懂的 Spring IoC 核心流程介绍

Spring IoC源码学习:总览

Spring IoC源码学习ApplicationContext刷新前的配置

Spring IoC源码学习obtainFreshBeanFactory详解

Spring IoC源码学习parseDefaultElement详解

Spring IoC源码学习parseCustomElement详解

Spring IoC源码学习:context:component-scan节点详解

Spring IoC源码学习invokeBeanFactoryPostProcessors详解

Spring IoC源码学习registerBeanPostProcessors详解

Spring IoC源码学习finishBeanFactoryInitialization详解

Spring IoC源码学习getBean详解

Spring IoC源码学习createBean详解(上)

Spring IoC源码学习createBean详解(下)

Spring IoC源码学习:@Autowire 详解

Spring IoC源码学习:finishRefresh 详解

 

前言


接着Spring IoCobtainFreshBeanFactory详解继续往下解析,本文来到 parseDefaultElement 方法。该方法是解析默认命名空间节点的方法,是加载 bean 定义模块的最核心方法。

 

正文


首先让我们回到Spring IoCobtainFreshBeanFactory详解文末的 parseBeanDefinitions 方法。

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    // 1.默认命名空间的处理
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        // 遍历root的子节点列表
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                if (delegate.isDefaultNamespace(ele)) {
                    // 1.1 默认命名空间节点的处理,例如: <bean id="test" class="" />
                    parseDefaultElement(ele, delegate);
                }
                else {
                    // 1.2 自定义命名空间节点的处理,例如:<context:component-scan/>、<aop:aspectj-autoproxy/>
                    delegate.parseCustomElement(ele);
                }
            }
        }
    } else {
        // 2.自定义命名空间的处理
        delegate.parseCustomElement(root);
    }
}

1.1 默认命名空间节点的处理,见下面 parseDefaultElement 方法。

 

parseDefaultElement


private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    // 1.对import标签的处理
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    // 2.对alias标签的处理
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
    }
    // 3.对bean标签的处理(最复杂最重要)
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    // 4.对beans标签的处理
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // recurse
        doRegisterBeanDefinitions(ele);
    }
}

可以看到默认命名空间的一级节点只有4种:importaliasbeanbeans。这4种节点中,最重要、最复杂的就是 <bean> 节点,本文只会介绍 <bean> 节点的处理,理解了<bean> 节点后,其他的都不难理解。另外,<beans> 节点只是递归调用之前的 doRegisterBeanDefinitions 方法,因此无需再介绍。


接下来,让我们从 processBeanDefinition(ele, delegate) 方法正式开始。

 

processBeanDefinition


protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 1.进行节点定义解析, 经过这个方法后,bdHolder会包含一个Bean节点的所有属性,例如name、class、id
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        // 2.若存在默认标签的子节点下再有自定义属性,需要再次对自定义标签再进行解析(基本不用,不做深入解析)
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // Register the final decorated instance.
            // 3.解析节点定义完成后,需要对解析后的bdHolder进行注册
            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));
    }
}

1. 进行节点定义解析,见代码块1详解

2. 例如下图这种,基本不用,不做深入解析。

image.png


3. 解析节点定义完成后,需要对解析后的 bdHolder 进行注册,见代码块13详解

4. 发出响应事件,通知相关的监听器,不做深入解析。

 

代码块1parseBeanDefinitionElement


public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
    // 1.解析name和id属性
    // 解析id属性
    String id = ele.getAttribute(ID_ATTRIBUTE);
    // 解析name属性
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    // 分割name属性(通过逗号或分号)
    // 例如:<bean name="demoService,demoServiceAlias" class=""/>,分割后aliases为[demoService, demoServiceAlias]
    List<String> aliases = new ArrayList<String>();
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        aliases.addAll(Arrays.asList(nameArr));
    }
    // beanName默认使用id
    String beanName = id;
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        // 如果id为空,并且aliases不为空,则取aliases的第一个元素作为beanName,其他的仍作为别名
        beanName = aliases.remove(0);
        if (logger.isDebugEnabled()) {
            logger.debug("No XML 'id' specified - using '" + beanName +
                    "' as bean name and " + aliases + " as aliases");
        }
    }
    if (containingBean == null) {
        // 检查beanName和aliases是否在同一个 <beans> 下已经存在
        checkNameUniqueness(beanName, aliases, ele);
    }
    // 2.进一步解析bean的其他所有属性并统一封装至GenericBeanDefinition类型实例中
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
        if (!StringUtils.hasText(beanName)) {
            try {
                // 3.如果bean定义存在,但是beanName为空,则用Spring默认的生成规则为当前bean生成beanName
                if (containingBean != null) {
                    beanName = BeanDefinitionReaderUtils.generateBeanName(
                            beanDefinition, this.readerContext.getRegistry(), true);
                }
                else {
                    // Spring提供的生成规则生成beanName,例如:com.joonwhee.open.demo.service.impl.DemoServiceImpl#0
                    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)) {
                        // 如果Spring默认的生成规则生成的beanName为:类名加后缀,则将类名注册为别名
                        aliases.add(beanClassName);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Neither XML 'id' nor 'name' specified - " +
                            "using generated bean name [" + beanName + "]");
                }
            }
            catch (Exception ex) {
                error(ex.getMessage(), ele);
                return null;
            }
        }
        String[] aliasesArray = StringUtils.toStringArray(aliases);
        // 4.将bean定义、beanName、bean别名数组封装成BeanDefinitionHolder
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }
    return null;
}

1.解析 name id 属性,其中 name 属性可以通过分割符设置多个。如果 id 存在,则 使用 id 作为 beanNamename 属性分割后全部作为别名;如果 id 不存在,则将 name 属性分割后的第1个作为 beanName,剩下的全部作为别名。


举个例子:


1

<!-- 配置1 -->
<bean id="appleService" name="appleOne;appleTwo" class="com.joonwhee.AppleServiceImpl"/>
<!-- 配置2 -->
<bean name="bananaOne;bananaTwo" class="com.joonwhee.BananaServiceImpl"/>

配置1beanName=appleServicealiases=[appleOne, appleTwo]

配置2beanName=bananaOnealiases=[bananaTwo]


2.进一步解析 bean 的其他所有属性并统一封装至GenericBeanDefinition 类型实例中,见代码块2详解

 

代码块2parseBeanDefinitionElement


public AbstractBeanDefinition parseBeanDefinitionElement(
        Element ele, String beanName, BeanDefinition containingBean) {
    this.parseState.push(new BeanEntry(beanName));
    String className = null;
    // 1.解析class、parent属性
    // 解析class属性
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }
    try {
        String parent = null;
        // 解析parent属性
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }
        // 2.创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);
        // 3.解析bean的各种属性
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        // 提取description
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
        // 解析元数据子节点(基本不用, 不深入介绍)
        parseMetaElements(ele, bd);
        // 解析lookup-method子节点(基本不用, 不深入介绍)
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        // 解析replaced-method子节点(基本不用, 不深入介绍)
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
        // 4.解析constructor-arg子节点
        parseConstructorArgElements(ele, bd);
        // 5.解析property子节点
        parsePropertyElements(ele, bd);
        // 解析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;
}

1.解析了classparent属性,因为第2步创建AbstractBeanDefinition 需要用到这两个属性,否则,这两个属性可以放到第3步一起解析。


2.创建用于承载属性的 AbstractBeanDefinition 类型的GenericBeanDefinition。比较简单,直接 new 一个 GenericBeanDefinition,如果className classLoader 不为空,则通过反射构建出 BeanClass,并设置为 GenericBeanDefinition 的属性。


3.解析 bean 的剩余属性,见代码块3详解

4.解析 constructor-arg 子节点,见代码块4详解

5.解析 property 子节点,见代码块11详解

 

代码块3parseBeanDefinitionAttributes


public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
        BeanDefinition containingBean, AbstractBeanDefinition bd) {
    // 解析singleton属性
    if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
        // singleton属性已经不支持, 如果使用了会直接抛出异常, 请使用scope属性代替
        error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
    }
    // 解析scope属性
    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属性, 默认为false
    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));
    // 解析dependency-check属性
    String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
    bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
    // 解析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);
        if (!"".equals(initMethodName)) {
            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));
    }
    // 解析factory-bean属性
    if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
        bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
    }
    return bd;
}

内容比较简单,就是从节点 ele 拿到所有的属性值,塞给AbstractBeanDefinition 的对应属性。这些属性的使用如下图。

image.png


代码块4parseConstructorArgElements


public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
    // 拿到beanEle节点的所有子节点
    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);
        }
    }
}

拿到 beanEle 节点的所有子节点,遍历解析所有是 constructor-arg节点的子节点,见代码块5详解


例子:

constructor-arg 的使用如下图所示,constructor-arg 节点类似于构造函数,bean 中必须要有相应的构造函数才可以使用,否则会报错。


image.png

image.png


代码块5parseConstructorArgElement


public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
    // 1.提取基础属性index、type、name属性值
    // 提取index属性
    String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
    // 提取type属性
    String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
    // 提取name属性
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    if (StringUtils.hasLength(indexAttr)) {
        try {
            int index = Integer.parseInt(indexAttr);
            if (index < 0) {
                error("'index' cannot be lower than 0", ele);
            }
            else {
                try {
                    // 2.index不为空的处理
                    this.parseState.push(new ConstructorArgumentEntry(index));
                    // 2.1解析ele节点对应的属性值
                    Object value = parsePropertyValue(ele, bd, null);
                    // 2.2使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素
                    ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
                    // 2.3将type属性封装到ConstructorArgumentValues.ValueHolder
                    if (StringUtils.hasLength(typeAttr)) {
                        valueHolder.setType(typeAttr);
                    }
                    // 2.4将name属性封装到ConstructorArgumentValues.ValueHolder
                    if (StringUtils.hasLength(nameAttr)) {
                        valueHolder.setName(nameAttr);
                    }
                    valueHolder.setSource(extractSource(ele));
                    // 2.5判断index是否重复指定, 如果是则抛出异常
                    if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
                        error("Ambiguous constructor-arg entries for index " + index, ele);
                    }
                    else {
                        // 将index和valueHolder以key-value形式添加至当前BeanDefinition的constructorArgumentValues
                        // 的indexedArgumentValues属性中,(用于上面判断index是否重复指定)
                        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 {
            // 3.index为空的处理
            this.parseState.push(new ConstructorArgumentEntry());
            // 3.1解析ele节点对应的属性值
            Object value = parsePropertyValue(ele, bd, null);
            // 3.2使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素
            ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
            // 3.3将type属性封装到ConstructorArgumentValues.ValueHolder
            if (StringUtils.hasLength(typeAttr)) {
                valueHolder.setType(typeAttr);
            }
            // 3.4将name属性封装到ConstructorArgumentValues.ValueHolder
            if (StringUtils.hasLength(nameAttr)) {
                valueHolder.setName(nameAttr);
            }
            valueHolder.setSource(extractSource(ele));
            // 3.5将valueHolder添加至当前BeanDefinition的constructorArgumentValues的genericArgumentValues属性中
            // 与上面的indexedArgumentValues类似,上面有index存为map,这边没index存为list
            bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
        }
        finally {
            this.parseState.pop();
        }
    }
}

1.首先拿到基础属性 indextypename 的属性值。


2.index不为空的处理:


2.1 首先解析 ele 节点的值,可以看代码块4里的图,每个 constructor-arg 节点必然有一个属性值,可能是通过 value 属性、ref 属性、list 属性等。见代码块6详解。

2.5 判断index是否重复指定,如果是则抛出异常;如果不重复,则将 index valueHolder key-value 形式添加至当前BeanDefinition constructorArgumentValues indexedArgumentValues 属性中(用于前面判断index是否重复指定)。


3.index为空的处理。基本与2相同,不在赘述。

 

代码块6parsePropertyValue

public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
    String elementName = (propertyName != null) ?
            "<property> element for property '" + propertyName + "'" :
            "<constructor-arg> element";
    // Should only have one child element: ref, value, list, etc.
    // 1.拿到ele节点的子节点,例如list、map
    NodeList nl = ele.getChildNodes();
    Element subElement = null;
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        // 跳过description或者meta节点
        if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
                !nodeNameEquals(node, META_ELEMENT)) {
            // Child element is what we're looking for.
            if (subElement != null) {
                // 只能有1个子节点,否则抛出异常
                error(elementName + " must not contain more than one sub-element", ele);
            } else {
                // 找到子节点,赋值给subElement
                subElement = (Element) node;
            }
        }
    }
    // 2.解析constructor-arg上的ref属性
    boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
    // 3.解析constructor-arg上的value属性
    boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
    // 4.合法性校验。在constructor-arg上:ref属性、value属性、子节点,三者只能有1个,因为这三个都是用来表示该节点的值。
    if ((hasRefAttribute && hasValueAttribute) ||
            ((hasRefAttribute || hasValueAttribute) && subElement != null)) {
        error(elementName +
                " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
    }
    if (hasRefAttribute) {
        // 5.ref属性的处理,使用RuntimeBeanReference封装对应的ref值(该ref值指向另一个bean的beanName),
        // RuntimeBeanReference起到占位符的作用,ref指向的beanName将在运行时被解析成真正的bean实例引用
        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;
    } else if (hasValueAttribute) {
        // 6.value属性的处理,使用TypedStringValue封装
        TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
        valueHolder.setSource(extractSource(ele));
        return valueHolder;
    } else if (subElement != null) {
        // 7.解析子节点
        return parsePropertySubElement(subElement, bd);
    } else {
        // 8.既没有ref属性,也没有value属性,也没有子节点,没法获取ele节点的值,直接抛异常
        // Neither child element nor "ref" or "value" attribute found.
        error(elementName + " must specify a ref or value", ele);
        return null;
    }
}

1.拿到 ele 节点的子节点,并赋值给变量 subElement。例如下图中 index="3" 的节点就有子节点,子节点为 list,其他 4 个都没有子节点。

image.png

7.解析子节点,见代码块7详解

 

代码块7parsePropertySubElement


public Object parsePropertySubElement(Element ele, BeanDefinition bd) {
    return parsePropertySubElement(ele, bd, null);
}
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
    // 1.校验是否为默认的命名空间,如果不是则走解析自定义节点代码
    if (!isDefaultNamespace(ele)) {
        return parseNestedCustomElement(ele, bd);
    }
    // 2.解析bean节点
    else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
        BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
        if (nestedBd != null) {
            nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
        }
        return nestedBd;
    }
    // 3.解析ref节点
    else if (nodeNameEquals(ele, REF_ELEMENT)) {
        // 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 the same XML file.
            refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
            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', 'local' 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;
    }
    // 4.解析idref节点
    else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
        return parseIdRefElement(ele);
    }
    // 5.解析value节点
    else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
        return parseValueElement(ele, defaultValueType);
    }
    // 6.解析null节点
    else if (nodeNameEquals(ele, NULL_ELEMENT)) {
        // 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;
    }
    // 7.解析array节点
    else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
        return parseArrayElement(ele, bd);
    }
    // 8.解析list节点
    else if (nodeNameEquals(ele, LIST_ELEMENT)) {
        return parseListElement(ele, bd);
    }
    // 9.解析set节点
    else if (nodeNameEquals(ele, SET_ELEMENT)) {
        return parseSetElement(ele, bd);
    }
    // 10.解析map节点
    else if (nodeNameEquals(ele, MAP_ELEMENT)) {
        return parseMapElement(ele, bd);
    }
    // 11.解析props节点
    else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
        return parsePropsElement(ele);
    }
    else {
        // 12.未知属性,抛异常
        error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
        return null;
    }
}

1.解析自定义命名空间节点。之后会介绍该内容,本处暂不介绍。

2.解析 bean 节点,之前已经走过该方法,见代码块1详解

5.解析 value 节点,见代码块8详解

8.解析 list 节点,7 11 的解析都比较类似,这边拿常用的 list 来介绍。见代码块10详解

 

代码块8parseValueElement


public Object parseValueElement(Element ele, String defaultTypeName) {
    // It's a literal value.
    // 拿到ele节点值
    String value = DomUtils.getTextValue(ele);
    // 拿到ele节点的type属性
    String specifiedTypeName = ele.getAttribute(TYPE_ATTRIBUTE);
    String typeName = specifiedTypeName;
    if (!StringUtils.hasText(typeName)) {
        // ele节点没有type属性则则使用入参defaultTypeName
        typeName = defaultTypeName;
    }
    try {
        // 1.使用value和type构建TypedStringValue
        TypedStringValue typedValue = buildTypedStringValue(value, typeName);
        typedValue.setSource(extractSource(ele));
        typedValue.setSpecifiedTypeName(specifiedTypeName);
        return typedValue;
    }
    catch (ClassNotFoundException ex) {
        error("Type class [" + typeName + "] not found for <value> element", ele, ex);
        return value;
    }
}

1.使用 value typeName 构建 TypedStringValue见代码块9详解

 

代码块9buildTypedStringValue


protected TypedStringValue buildTypedStringValue(String value, String targetTypeName)
        throws ClassNotFoundException {
    ClassLoader classLoader = this.readerContext.getBeanClassLoader();
    TypedStringValue typedValue;
    // 1.targetTypeName为空,则只使用value来构建TypedStringValue
    if (!StringUtils.hasText(targetTypeName)) {
        typedValue = new TypedStringValue(value);
    }
    // 2.targetTypeName不为空,并且classLoader不为null
    else if (classLoader != null) {
        // 2.1 利用反射,构建出type的Class,如果type是基本类型,或者 java.lang 包下的常用类,
        // 可以直接从缓存(primitiveTypeNameMap、commonClassCache)中获取
        Class<?> targetType = ClassUtils.forName(targetTypeName, classLoader);
        typedValue = new TypedStringValue(value, targetType);
    } else {
        typedValue = new TypedStringValue(value, targetTypeName);
    }
    return typedValue;
}

代码块10parseListElement


public List<Object> parseListElement(Element collectionEle, BeanDefinition bd) {
    // 1.拿到collectionEle节点的value-type,顾名思义,该属性就是该list节点下的value的类型
    String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
    // 2.拿到collectionEle节点的所有子节点, 一般为<value>
    NodeList nl = collectionEle.getChildNodes();
    // 3.new一个ManagedList,用于存放字节点的值
    ManagedList<Object> target = new ManagedList<Object>(nl.getLength());
    target.setSource(extractSource(collectionEle));
    target.setElementTypeName(defaultElementType);
    target.setMergeEnabled(parseMergeAttribute(collectionEle));
    // 4.解析子节点集合
    parseCollectionElements(nl, target, bd, defaultElementType);
    return target;
}
protected void parseCollectionElements(
        NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {
    // 4.1 遍历elementNodes
    for (int i = 0; i < elementNodes.getLength(); i++) {
        Node node = elementNodes.item(i);
        // 4.2 跳过description节点
        if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {
            // 4.3 调用parsePropertySubElement方法对节点进行解析, 正常list的子节点为<value>节点会直接走到value节点的解析
            // 如果list的子节点还是list,则相当于递归在走到此方法
            target.add(parsePropertySubElement((Element) node, bd, defaultElementType));
        }
    }
}

4.3 调用 parsePropertySubElement 方法对节点进行解析,见代码块7详解

正常情况下,list 里面应该是 value节点(见下图),则会走到代码块8解析出对应的value,然后结束。特殊情况下,可能 list 里面还是 list,则相当于递归在走到此方法。

image.png

至此,代码块4  代码块10 完成了constructor-arg节点的解析,让我们回到代码块2的第5点,继续解析 property 子节点。

 

代码块11parsePropertyElements


public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
    // 拿到beanEle节点的所有子节点
    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);
        }
    }
}

拿到 beanEle 节点的所有子节点,遍历解析所有是 property 节点的子节点,见代码块12详解

property 的使用如下图所示,property 节点类似于set方法,bean 中的属性必须要有 set 方法才可以使用,否则会报错。

image.png


代码块12parsePropertyElement


public void parsePropertyElement(Element ele, BeanDefinition bd) {
    // 1.拿到name属性
    String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
    if (!StringUtils.hasLength(propertyName)) {
        // name属性为必要属性,如果没有配置,则抛出异常
        error("Tag 'property' must have a 'name' attribute", ele);
        return;
    }
    this.parseState.push(new PropertyEntry(propertyName));
    try {
        // 2.校验在相同bean节点下,是否存在相同的name属性,如果存在则抛出异常
        if (bd.getPropertyValues().contains(propertyName)) {
            error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
            return;
        }
        // 3.解析属性值
        Object val = parsePropertyValue(ele, bd, propertyName);
        // 4.将解析的属性值和属性name封装成PropertyValue
        PropertyValue pv = new PropertyValue(propertyName, val);
        // 5.解析meta节点(基本不用,不深入解析)
        parseMetaElements(ele, pv);
        pv.setSource(extractSource(ele));
        // 6.将解析出来的PropertyValue,添加到BeanDefinition的propertyValues属性中(上面的重复校验用到)
        bd.getPropertyValues().addPropertyValue(pv);
    }
    finally {
        this.parseState.pop();
    }
}

3.解析属性值,上文已经介绍过该方法,见代码块6详解

 

代码块13registerBeanDefinition


public static void registerBeanDefinition(
        BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
        throws BeanDefinitionStoreException {
    // Register bean definition under primary name.
    // 1.拿到beanName
    String beanName = definitionHolder.getBeanName();
    // 2.注册beanName、BeanDefinition到缓存中(核心逻辑),实现类为; DefaultListableBeanFactory
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    // Register aliases for bean name, if any.
    // 注册bean名称的别名(如果有的话)
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            // 3.注册bean的beanName和对应的别名映射到缓存中(缓存:aliasMap)
            registry.registerAlias(beanName, alias);
        }
    }
}

2.注册 beanNameBeanDefinition 到缓存中,见代码块14详解

3.如果有别名,则注册 bean beanName 和对应的别名映射到 aliasMap 缓存中,见代码块16详解

 

代码块14registerBeanDefinition


@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {
    // 1.beanName和beanDefinition为空校验
    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            // 注册前的最后校验
            ((AbstractBeanDefinition) beanDefinition).validate();
        } catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                    "Validation of bean definition failed", ex);
        }
    }
    BeanDefinition oldBeanDefinition;
    // 首先根据beanName从beanDefinitionMap缓存中尝试获取
    oldBeanDefinition = this.beanDefinitionMap.get(beanName);
    if (oldBeanDefinition != null) {
        // 2.beanName存在于缓存中
        if (!isAllowBeanDefinitionOverriding()) {
            // 如果不允许相同beanName重新注册,则直接抛出异常
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                    "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                            "': There is already [" + oldBeanDefinition + "] bound.");
        } else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
            // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                        "' with a framework-generated bean definition: replacing [" +
                        oldBeanDefinition + "] with [" + beanDefinition + "]");
            }
        } else if (!beanDefinition.equals(oldBeanDefinition)) {
            if (this.logger.isInfoEnabled()) {
                this.logger.info("Overriding bean definition for bean '" + beanName +
                        "' with a different definition: replacing [" + oldBeanDefinition +
                        "] with [" + beanDefinition + "]");
            }
        } else {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Overriding bean definition for bean '" + beanName +
                        "' with an equivalent definition: replacing [" + oldBeanDefinition +
                        "] with [" + beanDefinition + "]");
            }
        }
        // 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存(以供后续创建bean时使用)
        this.beanDefinitionMap.put(beanName, beanDefinition);
    } else {
        // 3.beanName不存在于缓存中
        if (hasBeanCreationStarted()) {
            // 3.1 bean创建阶段已经开始
            // Cannot modify startup-time collection elements anymore (for stable iteration)
            synchronized (this.beanDefinitionMap) {
                // 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存
                this.beanDefinitionMap.put(beanName, beanDefinition);
                // 将本次传进来的beanName 加入beanDefinitionNames缓存
                List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                // 将beanName从manualSingletonNames缓存移除
                if (this.manualSingletonNames.contains(beanName)) {
                    Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
                    updatedSingletons.remove(beanName);
                    this.manualSingletonNames = updatedSingletons;
                }
            }
        } else {
            // 3.2 bean创建阶段还未开始
            // Still in startup registration phase
            // 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存
            this.beanDefinitionMap.put(beanName, beanDefinition);
            // 将本次传进来的beanName 加入beanDefinitionNames缓存
            this.beanDefinitionNames.add(beanName);
            // 将beanName从manualSingletonNames缓存移除
            this.manualSingletonNames.remove(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }
    // 4.如果存在相同beanName的BeanDefinition,并且beanName已经存在单例对象,则将该beanName对应的缓存信息、单例对象清除,
    // 因为这些对象都是通过oldBeanDefinition创建出来的,需要被覆盖掉的,
    // 我们需要用新的BeanDefinition(也就是本次传进来的beanDefinition)来创建这些缓存和单例对象
    if (oldBeanDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
}

这个方法会将 beanName 添加到beanDefinitionNames 缓存,将 beanName BeanDefinition 的映射关系添加到beanDefinitionMap 缓存。


如果 beanName不重复(一般不会重复),对于我们当前正在解析的 obtainFreshBeanFactory 方法来说,因为 bean 创建还未开始,因此会走到 3.2 进行缓存的注册。


4.如果 beanName 重复,并且该 beanName 已经存在单例对象,则会调用 resetBeanDefinition 方法,见代码块15详解

 

代码块15resetBeanDefinition


protected void resetBeanDefinition(String beanName) {
    // Remove the merged bean definition for the given bean, if already created.
    // 1.删除beanName的mergedBeanDefinitions缓存(如果有的话)
    clearMergedBeanDefinition(beanName);
    // Remove corresponding bean from singleton cache, if any. Shouldn't usually
    // be necessary, rather just meant for overriding a context's default beans
    // (e.g. the default StaticMessageSource in a StaticApplicationContext).
    // 2.从单例缓存中删除该beanName对应的bean(如果有的话)
    destroySingleton(beanName);
    // Reset all bean definitions that have the given bean as parent (recursively).
    // 3.重置beanName的所有子Bean定义(递归)
    for (String bdName : this.beanDefinitionNames) {
        if (!beanName.equals(bdName)) {
            BeanDefinition bd = this.beanDefinitionMap.get(bdName);
            // 当前遍历的BeanDefinition的parentName为beanName,则递归调用resetBeanDefinition进行重置
            if (beanName.equals(bd.getParentName())) {
                resetBeanDefinition(bdName);
            }
        }
    }
}

比较简单,将该 beanName mergedBeanDefinitions 缓存信息删除、单例缓存删除。如果存在子 bean 定义,则递归重置。实际开发过程中,基本不会出现 beanName 相同的情况,因此基本不会走到该方法。

 

代码块16registerAlias


@Override
public void registerAlias(String name, String alias) {
    Assert.hasText(name, "'name' must not be empty");
    Assert.hasText(alias, "'alias' must not be empty");
    // 1.如果别名和beanName相同,则不算别名,从aliasMap缓存中移除
    if (alias.equals(name)) {
        this.aliasMap.remove(alias);
    }
    else {
        String registeredName = this.aliasMap.get(alias);
        if (registeredName != null) {
            if (registeredName.equals(name)) {
                // An existing alias - no need to re-register
                // 2.如果别名已经注册过,直接返回
                return;
            }
            // 3.如果存在相同的别名,并且不允许别名覆盖,则抛出异常
            if (!allowAliasOverriding()) {
                throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
                        name + "': It is already registered for name '" + registeredName + "'.");
            }
        }
        // 4.检查name和alias是否存在循环引用。例如A的别名为B,B的别名为A
        checkForAliasCircle(name, alias);
        // 5.将别名和beanName的映射放到aliasMap缓存中
        this.aliasMap.put(alias, name);
    }
}

将别名和 beanName 注册到 aliasMap 缓存。

 

总结


我们可以重新梳理一下思路,我们首先将 xml 中的 bean 配置信息进行了解析,并构建了AbstractBeanDefinitionGenericBeanDefinition对象来存放所有解析出来的属性。


然后,我们将 AbstractBeanDefinition beanNamealiasesArray 构建成BeanDefinitionHolder 对象并返回。


最后,我们通过 BeanDefinitionHolder BeanDefinition beanName 注册到 BeanFactory 中,也就是存放到缓存中。


执行完 parseDefaultElement 方法,我们得到了两个重要的缓存:

·       beanDefinitionNames 缓存。

·       beanDefinitionMap 缓存。

这两个缓存在之后的 IoC 构建过程中会发挥很重要的作用,大家在这边先有个印象。

相关文章
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
86 2
|
2月前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
5天前
|
XML Java 数据格式
【SpringFramework】Spring IoC-基于XML的实现
本文主要讲解SpringFramework中IoC和DI相关概念,及基于XML的实现方式。
94 69
|
3天前
|
Java Spring 容器
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
35 21
|
9天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
8天前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
29天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
51 2
|
2月前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
69 9
|
2月前
|
XML 缓存 Java
搞透 IOC、Spring IOC ,看这篇就够了!
本文详细解析了Spring框架的核心内容——IOC(控制反转)及其依赖注入(DI)的实现原理,帮助读者理解如何通过IOC实现组件解耦,提高程序的灵活性和可维护性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
3月前
|
前端开发 Java 数据库
SpringBoot学习
【10月更文挑战第7天】Spring学习
45 9