spring源码(6)bean标签其他子标签的解析

spring bean子标签 loopup-method、replaced-method基本用法参见:http://blog.csdn.net/disiwei1012/article/details/70495940

本节介绍bean标签的其他子标签的解析

这里写图片描述

1.子元素meta解析

<bean id="test" class="com.demo.test">
    <meta key="testStr" value="aaa"/>
</bean>

//解析子元素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;
            //key属性
            String key = metaElement.getAttribute(KEY_ATTRIBUTE);
            //value属性               
            String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
            //构造BeanMetadataAttribute
            BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
            attribute.setSource(extractSource(metaElement));
            attributeAccessor.addMetadataAttribute(attribute);
        }
    }
}

2.子元素loopup-method解析

<bean id="test" class="com.demo.test">
    <lookup-method name="getBean" bean="teacher"/>
</bean>

<bean id="teacher" class="com.test.teacher"/>

//解析子元素loopup-method
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());

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)) {
            Element ele = (Element) node;
            //属性name
            String methodName = ele.getAttribute(NAME_ATTRIBUTE);
            //属性bean
            String beanRef = ele.getAttribute(BEAN_ELEMENT);
            LookupOverride override = new LookupOverride(methodName, beanRef);
            override.setSource(extractSource(ele));
            overrides.addOverride(override);
        }
    }
}

3.子元素replaced-method解析

<bean id="test" class="com.demo.test">
    <replaced-method name="changeMe" replacer="replacer"/>
</bean>

<bean id="replacer" class="com.test.replacer"/>

//解析子元素replaced-method
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

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;
            //name属性
            String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
            //replacer属性
            String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
            ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
            //获取arg-type标签,参数类型
            // 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);
        }
    }
}

4.子元素constructor-arg解析

4.1 举例说明

举个例子的话,会更直观一点:

public class Man {  

    private String name ;  
    private int age;  
    private List hobby;  
    private Map  friends;  
    private Set  set;  
    private boolean ifMarried;  

    public Man() {  

    }  

   public Man(String name, int age,List hobby,Map friends,Set    set,boolean ifMarried){  
        this.name = name;  
        this.age = age;  
        this.hobby = hobby;  
        this.friends = friends;  
        this.set = set;  
        this.ifMarried = ifMarried;  
   }  

    public String getInfo(){  

        String info = "姓名:"+this.name+"\n年龄:"+this.age+"\n爱好:"+this.hobby+"\n朋友:"+this.friends+"\n婚否:"+this.ifMarried+"\n其他的:"+this.set;  
           return info;  
   }  
}


<bean id="man" class="com.spring.test.Man">  
    <constructor-arg value="zzy" index="0"></constructor-arg>  
    <constructor-arg value="10"  index="1"></constructor-arg>  

    <constructor-arg>  
         <list>  
            <value>movie</value>  
            <value>music</value>  
         </list>  
    </constructor-arg>  

    <constructor-arg>  
          <set>  
             <value>Lady is GaGa</value>  
             <value>GaGa is Lady</value>  
          </set>  
    </constructor-arg>  

    <constructor-arg>  
           <map>  
              <entry key="liuhua" value="man"></entry>  
              <entry key="xujinglei" value="female"></entry>  
           </map>  
    </constructor-arg>  

    <constructor-arg index="5" value="0"></constructor-arg>  
</bean>  

4.2 具体代码解析

对于construction-arg 子元素的解析,spring 是通过 BeanDefinitionParserDelegate. parseConstructorArgElements(Element beanEle, BeanDefinition bd); 方法来实现的:

/**
 * Parse constructor-arg sub-elements of the given bean element.
 */
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);
        }
    }
}

追踪下去如下:

/**
 * 解析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);

    //如果constructor-arg标签index属性有值
    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));
                    //解析constructor-arg标签其他属性值,和子标签
                    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);
        }
    }//如果constructor-arg标签index属性没有值
    else {
        try {
            this.parseState.push(new ConstructorArgumentEntry());
            //解析constructor-arg标签其他属性值,和子标签
            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();
        }
    }
}

从上面的代码上看,对构造函数中属性的解析,经历了以下几个过程:

如果指定了index属性
1. 解析constructor-arg标签
2. ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素
3. 将type、name、index属性一起封装到ConstructorArgumentValues.ValueHolder中。并将ValueHolder中添加至当前BeanDefinition的ConstructorArgumentValues的IndexedArgumentValue中

如果没有指定index属性
1. 解析constructor-arg标签
2. ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素
3. 将type、name、index属性一起封装到ConstructorArgumentValues.ValueHolder中。并将ValueHolder中添加至当前BeanDefinition的ConstructorArgumentValues的GenericArgumentValue中

如果指定了index属性是保存到IndexedArgumentValue中,否则保存到GenericArgumentValue。

public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
    String elementName = (propertyName != null) ?
                    "<property> element for property '" + propertyName + "'" :
                    "<constructor-arg> element";

    //一个constructor-arg标签只能有一个子标签:ref,value,list等
    NodeList nl = ele.getChildNodes();
    Element subElement = null;
    //判断是否只有一个子标签(忽略description和meta标签)
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
                !nodeNameEquals(node, META_ELEMENT)) {
            if (subElement != null) {
                error(elementName + " must not contain more than one sub-element", ele);
            }
            else {
                subElement = (Element) node;
            }
        }
    }

    //constructor-arg标签的ref属性
    boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
    //constructor-arg标签的value属性
    boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
    /**
     * 1.constructor-arg标签不能同时具有ref和value属性
     * 1.constructor-arg如果具有ref和value属性之一,则不能再有子元素(忽略description和meta标签)
     */
    if ((hasRefAttribute && hasValueAttribute) ||
            ((hasRefAttribute || hasValueAttribute) && subElement != null)) {
        error(elementName +
                " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
    }
    //解析constructor-arg标签的ref属性
    if (hasRefAttribute) {
        //获取ref属性值
        String refName = ele.getAttribute(REF_ATTRIBUTE);
        if (!StringUtils.hasText(refName)) {
            error(elementName + " contains empty 'ref' attribute", ele);
        }
        //使用RuntimeBeanReference封装ref属性
        RuntimeBeanReference ref = new RuntimeBeanReference(refName);
        ref.setSource(extractSource(ele));
        return ref;
    }
    //解析constructor-arg标签的value属性
    else if (hasValueAttribute) {
        //使用TypedStringValue封装value属性
        TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
        valueHolder.setSource(extractSource(ele));
        return valueHolder;
    }
    //解析constructor-arg标签的子元素
    else if (subElement != null) {
        return parsePropertySubElement(subElement, bd);
    }
    else {
        //如果即没有子元素、也没有ref、value属性,则返回null
        error(elementName + " must specify a ref or value", ele);
        return null;
    }
}

public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
    if (!isDefaultNamespace(ele)) {
        return parseNestedCustomElement(ele, bd);
    }
    else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
        BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
        if (nestedBd != null) {
            nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
        }
        return nestedBd;
    }
    //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;
    }
    //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;
    }
}

5.子元素propertyg解析

5.1 基本用法

public class Animal {

public String type;

public Set<Integer> age;

private Map<String, Integer> sell;

public Animal() {

}

/**
 * @return the type
 */
public String getType() {
    return type;
}

/**
 * @param type the type to set
 */
public void setType(String type) {
    this.type = type;
}

/**
 * @return the age
 */
public Set<Integer> getAge() {
    return age;
}

/**
 * @param age the age to set
 */
public void setAge(Set<Integer> age) {
    this.age = age;
}

/**
 * @return the sell
 */
public Map<String, Integer> getSell() {
    return sell;
}

/**
 * @param sell the sell to set
 */
public void setSell(Map<String, Integer> sell) {
    this.sell = sell;
}

/*
 * (non-Javadoc)
 * 
 * @see java.lang.Object#toString()
 */
@Override
public String toString() {
    return "Animal [type=" + type + ", age=" + age + ", sell=" + sell + "]";
}

}

<?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-2.5.xsd">

    <bean id="animal" class="test.property.Animal">
        <property name="type" value="cat"></property>
        <property name="age">
            <set>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </set>
        </property>
        <property name="sell">
            <map>
                <entry key="blue" value="111"></entry>
                <entry key="red" value="22"></entry>
            </map>
        </property>
    </bean>
</beans>

5.2 具体代码解析

/**
 * Parse property sub-elements of the given bean element.
 */
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);
        }
    }
}

/**
 * Parse a property element.
 */
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 {
        // 不容许多次对同一属性配置
        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();
    }
}

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.
    // 应该只有一个子元素:REF,值,列表等。
    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)) {
        /*
         * 1.不能同时有ref 又有 value 
         * 2.不能存在ref 或者 value 又有子元素
         */
        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);
        }
        // ref 属性的处理 , 使用RuntimeBeanReference封装对应的ref名称
        RuntimeBeanReference ref = new RuntimeBeanReference(refName);
        ref.setSource(extractSource(ele));
        return ref;
    }
    else if (hasValueAttribute) {
        // Value 属性的处理 , 使用TypedStringValue封装对应的
        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.
        // 对于没有ref 也没有子元素的,Spring只好丢出异常
        error(elementName + " must specify a ref or value", ele);
        return null;
    }
}

6.子元素qualifier解析

<bean id="test" class="com.demo.test">
    <qualifier type="org.Springframework.beans.factory.annotation.Qualifier" value="ts"/>
</bean>

public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) {
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) {
            parseQualifierElement((Element) node, bd);
        }
    }
}

public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
    String typeName = ele.getAttribute(TYPE_ATTRIBUTE);
    //必须要有type属性
    if (!StringUtils.hasLength(typeName)) {
        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属性
        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);
            //解析子标签attribute
            if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) {
                Element attributeEle = (Element) node;
                String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE);
                String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE);
                if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) {
                    BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
                    attribute.setSource(extractSource(attributeEle));
                    qualifier.addMetadataAttribute(attribute);
                }
                else {
                    error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
                    return;
                }
            }
        }
        bd.addQualifier(qualifier);
    }
    finally {
        this.parseState.pop();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值