欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring源码深度解析— IOC 之 默认标签解析(上)

程序员文章站 2023-10-18 22:33:58
概述 接前两篇文章 spring源码深度解析—Spring的整体架构和环境搭建 和 spring源码深度解析— IOC 之 容器的基本实现 本文主要研究Spring标签的解析,Spring的标签中有默认标签和自定义标签,两者的解析有着很大的不同,这次重点说默认标签的解析过程。 默认标签的解析是在De ......

概述

接前两篇文章  spring源码深度解析—spring的整体架构和环境搭建  和  spring源码深度解析— ioc 之 容器的基本实现

本文主要研究spring标签的解析,spring的标签中有默认标签和自定义标签,两者的解析有着很大的不同,这次重点说默认标签的解析过程。

默认标签的解析是在defaultbeandefinitiondocumentreader.parsedefaultelement函数中进行的,分别对4种不同的标签(import,alias,bean和beans)做了不同处理。我们先看下此函数的源码:

private void parsedefaultelement(element ele, beandefinitionparserdelegate delegate) {
    if (delegate.nodenameequals(ele, import_element)) {
        importbeandefinitionresource(ele);
    }
    else if (delegate.nodenameequals(ele, alias_element)) {
        processaliasregistration(ele);
    }
    else if (delegate.nodenameequals(ele, bean_element)) {
        processbeandefinition(ele, delegate);
    }
    else if (delegate.nodenameequals(ele, nested_beans_element)) {
        // recurse
        doregisterbeandefinitions(ele);
    }
}

bean标签的解析及注册

在4中标签中对bean标签的解析最为复杂也最为重要,所以从此标签开始深入分析,如果能理解这个标签的解析过程,其他标签的解析就迎刃而解了。对于bean标签的解析用的是processbeandefinition函数,首先看看函数processbeandefinition(ele,delegate),其代码如下:

protected void processbeandefinition(element ele, beandefinitionparserdelegate delegate) {
    beandefinitionholder bdholder = delegate.parsebeandefinitionelement(ele);
    if (bdholder != null) {
        bdholder = delegate.decoratebeandefinitionifrequired(ele, bdholder);
        try {
            // 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);
        }
        // send registration event.
        getreadercontext().firecomponentregistered(new beancomponentdefinition(bdholder));
    }
}

刚开始看这个函数体时一头雾水,没有以前的函数那样的清晰的逻辑,我们细致的理下逻辑,大致流程如下:
- 首先委托beandefinitiondelegate类的parsebeandefinitionelement方法进行元素的解析,返回beandefinitionholder类型的实例bdholder,经过这个方法后bdholder实例已经包含了我们配置文件中的各种属性了,例如class,name,id,alias等。
- 当返回的dbholder不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析。
- 当解析完成后,需要对解析后的bdholder进行注册,注册过程委托给了beandefinitionreaderutils的registerbeandefinition方法。
- 最后发出响应事件,通知相关的监听器已经加载完这个bean了。 

解析beandefinition

接下来我们就针对具体的方法进行分析,首先我们从元素解析及信息提取开始,也就是beandefinitionholder bdholder = delegate.parsebeandefinitionelement(ele),进入 beandefinitiondelegate 类的 parsebeandefinitionelement 方法。我们看下源码:

public beandefinitionholder parsebeandefinitionelement(element ele, @nullable beandefinition containingbean) {
    // 解析 id 属性
    string id = ele.getattribute(id_attribute);
    // 解析 name 属性
    string nameattr = ele.getattribute(name_attribute);

    // 分割 name 属性
    list<string> aliases = new arraylist<>();
    if (stringutils.haslength(nameattr)) {
        string[] namearr = stringutils.tokenizetostringarray(nameattr, multi_value_attribute_delimiters);
        aliases.addall(arrays.aslist(namearr));
    }

    string beanname = id;
    if (!stringutils.hastext(beanname) && !aliases.isempty()) {
        beanname = aliases.remove(0);
        if (logger.isdebugenabled()) {
            logger.debug("no xml 'id' specified - using '" + beanname +
                    "' as bean name and " + aliases + " as aliases");
        }
    }

    // 检查 name 的唯一性
    if (containingbean == null) {
        checknameuniqueness(beanname, aliases, ele);
    }

    // 解析 属性,构造 abstractbeandefinition
    abstractbeandefinition beandefinition = parsebeandefinitionelement(ele, beanname, containingbean);
    if (beandefinition != null) {
        // 如果 beanname 不存在,则根据条件构造一个 beanname
        if (!stringutils.hastext(beanname)) {
            try {
                if (containingbean != null) {
                    beanname = beandefinitionreaderutils.generatebeanname(
                            beandefinition, this.readercontext.getregistry(), true);
                }
                else {
                    beanname = this.readercontext.generatebeanname(beandefinition);
                    string beanclassname = beandefinition.getbeanclassname();
                    if (beanclassname != null &&
                            beanname.startswith(beanclassname) && beanname.length() > beanclassname.length() &&
                            !this.readercontext.getregistry().isbeannameinuse(beanclassname)) {
                        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);

        // 封装 beandefinitionholder
        return new beandefinitionholder(beandefinition, beanname, aliasesarray);
    }

    return null;
}

上述方法就是对默认标签解析的全过程了,我们分析下当前层完成的工作:
(1)提取元素中的id和name属性
(2)进一步解析其他所有属性并统一封装到genericbeandefinition类型的实例中
(3)如果检测到bean没有指定beanname,那么使用默认规则为此bean生成beanname。
(4)将获取到的信息封装到beandefinitionholder的实例中。
代码:abstractbeandefinition beandefinition = parsebeandefinitionelement(ele, beanname, containingbean);是用来对标签中的其他属性进行解析,我们详细看下源码:

public abstractbeandefinition parsebeandefinitionelement(
        element ele, string beanname, @nullable beandefinition containingbean) {

    this.parsestate.push(new beanentry(beanname));

    string classname = null;
    //解析class属性
    if (ele.hasattribute(class_attribute)) {
        classname = ele.getattribute(class_attribute).trim();
    }
    string parent = null;
    //解析parent属性
    if (ele.hasattribute(parent_attribute)) {
        parent = ele.getattribute(parent_attribute);
    }

    try {
        //创建用于承载属性的abstractbeandefinition类型的genericbeandefinition实例
        abstractbeandefinition bd = createbeandefinition(classname, parent);
        //硬编码解析bean的各种属性
        parsebeandefinitionattributes(ele, beanname, containingbean, bd);
        //设置description属性
        bd.setdescription(domutils.getchildelementvaluebytagname(ele, description_element));
        //解析元素
        parsemetaelements(ele, bd);
        //解析lookup-method属性
        parselookupoverridesubelements(ele, bd.getmethodoverrides());
        //解析replace-method属性
        parsereplacedmethodsubelements(ele, bd.getmethodoverrides());
        //解析构造函数的参数
        parseconstructorargelements(ele, bd);
        //解析properties子元素
        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;
}

接下来我们一步步分析解析过程。

bean详细解析过程

创建用于承载属性的beandefinition 

beandefinition是一个接口,在spring中此接口有三种实现:rootbeandefinition、childbeandefinition已经genericbeandefinition。而三种实现都继承了abstractbeandefinition,其中beandefinition是配置文件元素标签在容器中的内部表示形式。元素标签拥有class、scope、lazy-init等属性,beandefinition则提供了相应的beanclass、scope、lazyinit属性,beandefinition和<bean>中的属性一一对应。其中rootbeandefinition是最常用的实现类,他对应一般性的元素标签,genericbeandefinition是自2.5版本以后新加入的bean文件配置属性定义类,是一站式服务的。
在配置文件中可以定义父和字,父用rootbeandefinition表示,而子用childbeandefinition表示,而没有父的就使用rootbeandefinition表示。abstractbeandefinition对两者共同的类信息进行抽象。

spring通过beandefinition将配置文件中的配置信息转换为容器的内部表示,并将这些beandefinition注册到beandefinitionregistry中。spring容器的beandefinitionregistry就像是spring配置信息的内存数据库,主要是以map的形式保存,后续操作直接从beandefinitionresistry中读取配置信息。它们之间的关系如下图所示:

spring源码深度解析— IOC 之 默认标签解析(上)

因此,要解析属性首先要创建用于承载属性的实例,也就是创建genericbeandefinition类型的实例。而代码createbeandefinition(classname,parent)的作用就是实现此功能。我们详细看下方法体,代码如下:

protected abstractbeandefinition createbeandefinition(@nullable string classname, @nullable string parentname)
        throws classnotfoundexception {

    return beandefinitionreaderutils.createbeandefinition(
            parentname, classname, this.readercontext.getbeanclassloader());
}
public static abstractbeandefinition createbeandefinition(
        @nullable string parentname, @nullable string classname, @nullable classloader classloader) throws classnotfoundexception {

    genericbeandefinition bd = new genericbeandefinition();
    bd.setparentname(parentname);
    if (classname != null) {
        if (classloader != null) {
            bd.setbeanclass(classutils.forname(classname, classloader));
        }
        else {
            bd.setbeanclassname(classname);
        }
    }
    return bd;
}

各种属性的解析 

 当创建好了承载bean信息的实例后,接下来就是解析各种属性了,首先我们看下parsebeandefinitionattributes(ele, beanname, containingbean, bd);方法,代码如下:

 

public abstractbeandefinition parsebeandefinitionattributes(element ele, string beanname,
        @nullable beandefinition containingbean, abstractbeandefinition bd) {
    //解析singleton属性
    if (ele.hasattribute(singleton_attribute)) {
        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属性
    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));
    //解析dependson属性
    if (ele.hasattribute(depends_on_attribute)) {
        string dependson = ele.getattribute(depends_on_attribute);
        bd.setdependson(stringutils.tokenizetostringarray(dependson, multi_value_attribute_delimiters));
    }
    //解析autowirecandidate属性
    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));
    }
    //解析factory_bean属性
    if (ele.hasattribute(factory_bean_attribute)) {
        bd.setfactorybeanname(ele.getattribute(factory_bean_attribute));
    }

    return bd;
}

解析meta元素 

 在开始对meta元素解析分析前我们先简单回顾下meta属性的使用,简单的示例代码如下:

  <bean id="demo" class="com.yhl.myspring.demo.bean.mybeandemo">
      <property name="beanname" value="bean demo1"/>
      <meta key="demo" value="demo"/>
  </bean>

这段代码并不会提现在demo的属性中,而是一个额外的声明,如果需要用到这里面的信息时可以通过beandefinition的getattribute(key)方法获取,对meta属性的解析用的是:parsemetaelements(ele, bd);具体的方法体如下:

public void parsemetaelements(element ele, beanmetadataattributeaccessor attributeaccessor) {
    nodelist nl = ele.getchildnodes();
    for (int i = 0; i < nl.getlength(); i++) {
        node node = nl.item(i);
        if (iscandidateelement(node) && nodenameequals(node, meta_element)) {
            element metaelement = (element) node;
            string key = metaelement.getattribute(key_attribute);
            string value = metaelement.getattribute(value_attribute);
            beanmetadataattribute attribute = new beanmetadataattribute(key, value);
            attribute.setsource(extractsource(metaelement));
            attributeaccessor.addmetadataattribute(attribute);
        }
    }
}

解析replaced-method属性 

 在分析代码前我们还是先简单的了解下replaced-method的用法,其主要功能是方法替换:即在运行时用新的方法替换旧的方法。与之前的lookup-method不同的是此方法不仅可以替换返回的bean,还可以动态的更改原有方法的运行逻辑,我们看下使用:

//原有的changeme方法
public class testchangemethod {
    public void changeme()
    {
        system.out.println("changeme");
    }
}
//新的实现方法
public class replacerchangemethod implements methodreplacer {
    public object reimplement(object o, method method, object[] objects) throws throwable {
        system.out.println("i replace method");
        return null;
    }
}
//新的配置文件
<?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">

    <bean id="changeme" class="com.chenhao.spring.testchangemethod">
        <replaced-method name="changeme" replacer="replacer"/>
    </bean>
    <bean id="replacer" class="com.chenhao.spring.replacerchangemethod"></bean>
</beans>
//测试方法
public class testdemo {
    public static void main(string[] args) {
        applicationcontext context = new classpathxmlapplicationcontext("replaced-method.xml");

        testchangemethod test =(testchangemethod) context.getbean("changeme");

        test.changeme();
    }
}

接下来我们看下解析replaced-method的方法代码:

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)) {
            element replacedmethodele = (element) node;
            string name = replacedmethodele.getattribute(name_attribute);
            string callback = replacedmethodele.getattribute(replacer_attribute);
            replaceoverride replaceoverride = new replaceoverride(name, callback);
            // look for arg-type match elements.
            list<element> argtypeeles = domutils.getchildelementsbytagname(replacedmethodele, arg_type_element);
            for (element argtypeele : argtypeeles) {
                string match = argtypeele.getattribute(arg_type_match_attribute);
                match = (stringutils.hastext(match) ? match : domutils.gettextvalue(argtypeele));
                if (stringutils.hastext(match)) {
                    replaceoverride.addtypeidentifier(match);
                }
            }
            replaceoverride.setsource(extractsource(replacedmethodele));
            overrides.addoverride(replaceoverride);
        }
    }
}

我们可以看到无论是 look-up 还是 replaced-method 是构造了 methodoverride ,并最终记录在了 abstractbeandefinition 中的 methodoverrides 属性中

解析constructor-arg 

对构造函数的解析式非常常用,也是非常复杂的,我们先从一个简单配置构造函数的例子开始分析,代码如下:

public void parseconstructorargelement(element ele, beandefinition bd) {
    //提前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 {
                    this.parsestate.push(new constructorargumententry(index));
                    //解析ele对应的元素属性
                    object value = parsepropertyvalue(ele, bd, null);
                    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 {
                        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());
            object value = parsepropertyvalue(ele, bd, null);
            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));
            bd.getconstructorargumentvalues().addgenericargumentvalue(valueholder);
        }
        finally {
            this.parsestate.pop();
        }
    }
}

上述代码的流程可以简单的总结为如下:
(1)首先提取index、type、name等属性
(2)根据是否配置了index属性解析流程不同
如果配置了index属性,解析流程如下:
(1)使用parsepropertyvalue(ele, bd, null)方法读取constructor-arg的子元素
(2)使用constructorargumentvalues.valueholder封装解析出来的元素
(3)将index、type、name属性也封装进valueholder中,然后将valuehoder添加到当前beandefinition的constructorargumentvalues的indexedargumentvalues,而indexedargumentvalues是一个map类型

如果没有配置index属性,将index、type、name属性也封装进valueholder中,然后将valuehoder添加到当前beandefinition的constructorargumentvalues的genericargumentvalues中

public object parsepropertyvalue(element ele, beandefinition bd, @nullable string propertyname) {
    string elementname = (propertyname != null) ?
                    "<property> element for property '" + propertyname + "'" :
                    "<constructor-arg> element";

    // 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);
        //略过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) {
                error(elementname + " must not contain more than one sub-element", ele);
            }
            else {
                subelement = (element) node;
            }
        }
    }
    //解析ref属性
    boolean hasrefattribute = ele.hasattribute(ref_attribute);
    //解析value属性
    boolean hasvalueattribute = ele.hasattribute(value_attribute);
    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) {
        string refname = ele.getattribute(ref_attribute);
        if (!stringutils.hastext(refname)) {
            error(elementname + " contains empty 'ref' attribute", ele);
        }
        //使用runtimebeanreference来封装ref对应的bean
        runtimebeanreference ref = new runtimebeanreference(refname);
        ref.setsource(extractsource(ele));
        return ref;
    }
    else if (hasvalueattribute) {
        //使用typedstringvalue 来封装value属性
        typedstringvalue valueholder = new typedstringvalue(ele.getattribute(value_attribute));
        valueholder.setsource(extractsource(ele));
        return valueholder;
    }
    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)首先略过decription和meta属性
(2)提取constructor-arg上的ref和value属性,并验证是否存在
(3)存在ref属性时,用runtimebeanreference来封装ref
(4)存在value属性时,用typedstringvalue来封装
(5)存在子元素时,对于子元素的处理使用了方法parsepropertysubelement(subelement, bd);,其代码如下:

public object parsepropertysubelement(element ele, @nullable beandefinition bd) {
    return parsepropertysubelement(ele, bd, null);
}
public object parsepropertysubelement(element ele, @nullable beandefinition bd, @nullable string defaultvaluetype) {
    //判断是否是默认标签处理
    if (!isdefaultnamespace(ele)) {
        return parsenestedcustomelement(ele, bd);
    }
    //对于bean标签的处理
    else if (nodenameequals(ele, bean_element)) {
        beandefinitionholder nestedbd = parsebeandefinitionelement(ele, bd);
        if (nestedbd != null) {
            nestedbd = decoratebeandefinitionifrequired(ele, nestedbd, bd);
        }
        return nestedbd;
    }
    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 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;
    }
    //idref元素处理
    else if (nodenameequals(ele, idref_element)) {
        return parseidrefelement(ele);
    }
    //value元素处理
    else if (nodenameequals(ele, value_element)) {
        return parsevalueelement(ele, defaultvaluetype);
    }
    //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;
    }
    //array元素处理
    else if (nodenameequals(ele, array_element)) {
        return parsearrayelement(ele, bd);
    }
    //list元素处理
    else if (nodenameequals(ele, list_element)) {
        return parselistelement(ele, bd);
    }
    //set元素处理
    else if (nodenameequals(ele, set_element)) {
        return parsesetelement(ele, bd);
    }
    //map元素处理
    else if (nodenameequals(ele, map_element)) {
        return parsemapelement(ele, bd);
    }
    //props元素处理
    else if (nodenameequals(ele, props_element)) {
        return parsepropselement(ele);
    }
    else {
        error("unknown property sub-element: [" + ele.getnodename() + "]", ele);
        return null;
    }
}

解析子元素properties 

对于propertie元素的解析是使用的parsepropertyelements(ele, bd);方法,我们看下其源码如下:

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)) {
            parsepropertyelement((element) node, bd);
        }
    }
}

里面实际的解析是用的parsepropertyelement((element) node, bd);方法,继续跟踪代码:

public void parsepropertyelement(element ele, beandefinition bd) {
    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 {
        //不允许多次对同一属性配置
        if (bd.getpropertyvalues().contains(propertyname)) {
            error("multiple 'property' definitions for property '" + propertyname + "'", ele);
            return;
        }
        object val = parsepropertyvalue(ele, bd, propertyname);
        propertyvalue pv = new propertyvalue(propertyname, val);
        parsemetaelements(ele, pv);
        pv.setsource(extractsource(ele));
        bd.getpropertyvalues().addpropertyvalue(pv);
    }
    finally {
        this.parsestate.pop();
    }
}

我们看到代码的逻辑非常简单,在获取了propertie的属性后使用propertyvalue 进行封装,然后将其添加到beandefinition的propertyvaluelist中

推荐博客

  

解析子元素 qualifier

对于 qualifier 元素的获取,我们接触更多的是注解的形式,在使用 spring 架中进行自动注入时,spring 器中匹配的候选 bean 数目必须有且仅有一个,当找不到一个匹配的 bean 时, spring容器将抛出 beancreationexception 异常, 并指出必须至少拥有一个匹配的 bean。

spring 允许我们通过qualifier 指定注入 bean的名称,这样歧义就消除了,而对于配置方式使用如:

<bean id="mytestbean" class="com.chenhao.spring.mytestbean">
<qualifier type="org.springframework.beans.factory.annotation.qualifier" value="gf" /> </bean>

其解析过程与之前大同小异 这里不再重复叙述

至此我们便完成了对 xml 文档到 genericbeandefinition 的转换, 就是说到这里, xml 中所有的配置都可以在 genericbeandefinition的实例类中应找到对应的配置。

genericbeandefinition 只是子类实现,而大部分的通用属性都保存在了 bstractbeandefinition 中,那么我们再次通过 abstractbeandefinition 的属性来回顾一 下我们都解析了哪些对应的配置。

public abstract class abstractbeandefinition extends beanmetadataattributeaccessor
        implements beandefinition, cloneable {
        
    // 此处省略静态变量以及final变量
    
    @nullable
    private volatile object beanclass;
    /**
     * bean的作用范围,对应bean属性scope
     */
    @nullable
    private string scope = scope_default;
    /**
     * 是否是抽象,对应bean属性abstract
     */
    private boolean abstractflag = false;
    /**
     * 是否延迟加载,对应bean属性lazy-init
     */
    private boolean lazyinit = false;
    /**
     * 自动注入模式,对应bean属性autowire
     */
    private int autowiremode = autowire_no;
    /**
     * 依赖检查,spring 3.0后弃用这个属性
     */
    private int dependencycheck = dependency_check_none;
    /**
     * 用来表示一个bean的实例化依靠另一个bean先实例化,对应bean属性depend-on
     */
    @nullable
    private string[] dependson;
    /**
     * autowire-candidate属性设置为false,这样容器在查找自动装配对象时,
     * 将不考虑该bean,即它不会被考虑作为其他bean自动装配的候选者,
     * 但是该bean本身还是可以使用自动装配来注入其他bean的
     */
    private boolean autowirecandidate = true;
    /**
     * 自动装配时出现多个bean候选者时,将作为首选者,对应bean属性primary
     */
    private boolean primary = false;
    /**
     * 用于记录qualifier,对应子元素qualifier
     */
    private final map<string, autowirecandidatequalifier> qualifiers = new linkedhashmap<>(0);

    @nullable
    private supplier<?> instancesupplier;
    /**
     * 允许访问非公开的构造器和方法,程序设置
     */
    private boolean nonpublicaccessallowed = true;
    /**
     * 是否以一种宽松的模式解析构造函数,默认为true,
     * 如果为false,则在以下情况
     * interface itest{}
     * class itestimpl implements itest{};
     * class main {
     *     main(itest i) {}
     *     main(itestimpl i) {}
     * }
     * 抛出异常,因为spring无法准确定位哪个构造函数程序设置
     */
    private boolean lenientconstructorresolution = true;
    /**
     * 对应bean属性factory-bean,用法:
     * <bean id = "instancefactorybean" class = "example.chapter3.instancefactorybean" />
     * <bean id = "currenttime" factory-bean = "instancefactorybean" factory-method = "createtime" />
     */
    @nullable
    private string factorybeanname;
    /**
     * 对应bean属性factory-method
     */
    @nullable
    private string factorymethodname;
    /**
     * 记录构造函数注入属性,对应bean属性constructor-arg
     */
    @nullable
    private constructorargumentvalues constructorargumentvalues;
    /**
     * 普通属性集合
     */
    @nullable
    private mutablepropertyvalues propertyvalues;
    /**
     * 方法重写的持有者,记录lookup-method、replaced-method元素
     */
    @nullable
    private methodoverrides methodoverrides;
    /**
     * 初始化方法,对应bean属性init-method
     */
    @nullable
    private string initmethodname;
    /**
     * 销毁方法,对应bean属性destroy-method
     */
    @nullable
    private string destroymethodname;
    /**
     * 是否执行init-method,程序设置
     */
    private boolean enforceinitmethod = true;
    /**
     * 是否执行destroy-method,程序设置
     */
    private boolean enforcedestroymethod = true;
    /**
     * 是否是用户定义的而不是应用程序本身定义的,创建aop时候为true,程序设置
     */
    private boolean synthetic = false;
    /**
     * 定义这个bean的应用,application:用户,infrastructure:完全内部使用,与用户无关,
     * support:某些复杂配置的一部分
     * 程序设置
     */
    private int role = beandefinition.role_application;
    /**
     * bean的描述信息
     */
    @nullable
    private string description;
    /**
     * 这个bean定义的资源
     */
    @nullable
    private resource resource;
}

 

上一篇: Serverless

下一篇: 红牌