Spring4.3.x 浅析xml配置的解析过程(4)——解析bean标签及其所有子标签

来源:互联网 发布:怎样制作淘宝店招 编辑:程序博客网 时间:2024/05/22 07:35

概述


在使用ResourceLoader创建Resource对象一节中,我们探讨了Spring如何正确的查找我们指定的配置文件并为配置文件生成Resource对象。

在使用DocumentLoader创建Document对象一节中,我们又已经解析了Spring通过xerces如何把Resource对象中的XML内容转换成Document对象。

在浅析Spring4使用XmlBeanDefinitionReader解析xml配置一文中,我们知道XmlBeanDefinitionReader使用BeanDefinitionDocumentReader接口的默认实现DefaultBeanDefinitionDocumentReader把Document对象中包含的配置信息转换成BeanDefinition对象并把它注册到BeanDefintionRegistry对象中。在DefaultBeanDefinitionDocumentReader的实现中,它的责任是遍历xml根节点下的子节点,并把处理bean标签和自定义命名空间的标签(比如aop:,context:,p:等)的细节委托给BeanDefinitionParserDelegate对象,BeanDefinitionParserDelegate才是真正解析配置文件的地方。

下面我们就开始探讨BeanDefinitionParserDelegate解析bean标签的过程。

约定:为了提高本文的可读性,我把spring源码中定义的常量替换为对应的字面值。

(1)创建BeanDefinitionParserDelegate 对象
在DefaultBeanDefinitionDocumentReader中,调用createDelegate方法根据beans标签来创建和初始化BeanDefinitionParserDelegate 对象,见下面createDelegate方法的源码。

    protected BeanDefinitionParserDelegate createDelegate(            XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {        // 创建delegate对象        BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);        // 初始化delegate对象        delegate.initDefaults(root, parentDelegate);        return delegate;    }

createDelegate方法中的root参数为xml配置中<beans>标签,它首先实例化一个BeanDefinitionParserDelegate对象,然后调用这个对象的initDefaults方法来初始化默认值,这个方法的代码如下。

    public void initDefaults(Element root, BeanDefinitionParserDelegate parent) {        // 计算默认值        populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);        this.readerContext.fireDefaultsRegistered(this.defaults);    }
    protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) {        String lazyInit = root.getAttribute("default-lazy-init");        if ("default".equals(lazyInit)) {            // 继承外层<beans>标签的属性值,否则为false字符串            lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : "false");        }        defaults.setLazyInit(lazyInit);        String merge = root.getAttribute("default-merge");        if ("default".equals(merge)) {            // 继承外层<beans>标签的属性值,否则为false字符串            merge = (parentDefaults != null ? parentDefaults.getMerge() : "false");        }        defaults.setMerge(merge);        String autowire = root.getAttribute("default-autowire");        if ("default".equals(autowire)) {            // 继承外层<beans>标签的属性值,否则为no字符串            autowire = (parentDefaults != null ? parentDefaults.getAutowire() : "no");        }        defaults.setAutowire(autowire);        defaults.setDependencyCheck(root.getAttribute("default-dependency-check"));        if (root.hasAttribute("default-autowire-candidates")) {            defaults.setAutowireCandidates(root.getAttribute("default-autowire-candidates"));        } else if (parentDefaults != null) {            // 继承外层<beans>标签的属性值            defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates());        }        if (root.hasAttribute("default-init-method")) {            defaults.setInitMethod(root.getAttribute("default-init-method"));        } else if (parentDefaults != null) {            // 继承外层<beans>标签的属性值            defaults.setInitMethod(parentDefaults.getInitMethod());        }        if (root.hasAttribute("default-destroy-method")) {            defaults.setDestroyMethod(root.getAttribute("default-destroy-method"));        } else if (parentDefaults != null) {            // 继承外层<beans>标签的属性值            defaults.setDestroyMethod(parentDefaults.getDestroyMethod());        }        defaults.setSource(this.readerContext.extractSource(root));    }

populateDefaults方法获取<beans>标签的属性值,如果beans标签上没有指定属性值并且外层还有beans标签时,将沿用外层beans标签的。

(2)使用BeanDefinitionParserDelegate 对象处理<bean>标签
我们从DefaultBeanDefinitionDocumentReader使用BeanDefinitionParserDelegate解析<bean>标签的方法processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)开始,代码如下。

    /**    * 解析bean节点,并注册BeanDefinition对象    */    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {        // 创建BeanDefinitionHolder        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);        if (bdHolder != null) {            // 装饰BeanDefinition            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);            try {                // 注册已经创建好的BeanDefintion                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());            } catch (BeanDefinitionStoreException ex) {                getReaderContext().error("Failed to register bean definition with name '" +                        bdHolder.getBeanName() + "'", ele, ex);            }            // 发送BeanDefinition注册事件            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));        }    }

processBeanDefinition方法的ele参数为<bean>标签,这段代码分成三步。第一步,根据传入的Element对象(bean标签的)调用代理对象的parseBeanDefinitionElement(Element ele)方法创建BeanDefinitionHolder 对象,这个对象持有创建好的BeanDefinition对象、bean的id和bean的别名。

第二步,调用代理对象的decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder)来对BeanDefinition对象再加工,主要是解析<bean>标签中自定义属性和自定义标签。

第三步,调用工具类BeanDefinitionReaderUtils的registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)方法,这个方法用于注册创建好的BeanDefinition。

第三步已经在浅析Spring4使用XmlBeanDefinitionReader解析xml配置部分探讨了。这里我们深入的探讨前两步。

1. 创建BeanDefinitionHolder 对象


执行BeanDefinitionParserDelegate的parseBeanDefinitionElement(Element ele)方法,代码如下。

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {        return parseBeanDefinitionElement(ele, null);    }
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {        // 获取id属性        String id = ele.getAttribute("id");        // 获取name属性        String nameAttr = ele.getAttribute("name");        List<String> aliases = new ArrayList<String>();        if (StringUtils.hasLength(nameAttr)) {            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");            aliases.addAll(Arrays.asList(nameArr));        }        String beanName = id;        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {            // 使用第一个alias作为id            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) {            // 检查id和别名是否已经被使用了,如果已经被其他bean占用,则会抛出异常            checkNameUniqueness(beanName, aliases, ele);        }        // 创建BeanDefinition对象        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);        if (beanDefinition != null) {            if (!StringUtils.hasText(beanName)) {                // 配置中没有指定id属性                try {                    if (containingBean != null) {                        // bean是另一个bean的内部bean                        beanName = BeanDefinitionReaderUtils.generateBeanName(                                beanDefinition, this.readerContext.getRegistry(), true);                    }                    else {                        // 为一个顶层bean生成id                        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对象            // 此对象持有生成的BeanDefinition对象和id以及别名列表            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);        }        return null;    }

这部分代码主要是检查用户给的bean id是否已经被占用、为没有id属性值的bean创建id值以及调用parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean)方法来解析Element对象并创建BeanDefinition对象,最后创建一个BeanDefinitionHolder对象来封装BeanDefinition对象、bean id和bean别名。

parseBeanDefinitionElement方法是解析<bean>节点的主要方法,在这里我们重点探讨它。下面是BeanDefinitionParserDelegate的parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean)方法代码。

/*** 创建BeanDefinition对象**/public AbstractBeanDefinition parseBeanDefinitionElement(            Element ele, String beanName, BeanDefinition containingBean) {        this.parseState.push(new BeanEntry(beanName));        String className = null;        // 读取<bean>节点的class属性        if (ele.hasAttribute("class")) {            className = ele.getAttribute("class").trim();        }        try {            String parent = null;            // 读取<bean>节点的parent属性            if (ele.hasAttribute("parent")) {                parent = ele.getAttribute("parent");            }            // 创建一个GenericBeanDefinition对象            AbstractBeanDefinition bd = createBeanDefinition(className, parent);            // 解析<bean>节点的属性            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);            // 获取<desription>节点的值            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));            // 解析<meta>节点            parseMetaElements(ele, bd);            // 解析<lookup-method>节点            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());            // 解析<replaced-method>节点            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());            // 解析<constructor-arg>节点            parseConstructorArgElements(ele, bd);            // 解析<property>节点            parsePropertyElements(ele, bd);            // 解析<qualifier>节点            parseQualifierElements(ele, bd);            // 让BeanDefinition持有当前Resource对象            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对象。
parseBeanDefinitionElement方法制定了<bean>的解析流程,即BeanDefinition对象的创建和初始化流程,这个流程在parseBeanDefinitionElement方法中已经非常明确,主要有8步(除去<description>标签),这里我就不画流程图了,下面我们直接来探讨这个流程。

1.1 实例化BeanDefinition对象

parseBeanDefinitionElement方法调用BeanDefinitionParserDelegate的createBeanDefinition方法来创建BeanDefinition对象,这个方法的源码如下。

    protected AbstractBeanDefinition createBeanDefinition(String className, String parentName)            throws ClassNotFoundException {        return BeanDefinitionReaderUtils.createBeanDefinition(                parentName, className, this.readerContext.getBeanClassLoader());    }

createBeanDefinition方法通过调用工具类BeanDefinitionReaderUtils的createBeanDefinition静态方法来创建BeanDefinition对象,代码如下。

    public static AbstractBeanDefinition createBeanDefinition(            String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {        GenericBeanDefinition bd = new GenericBeanDefinition();        bd.setParentName(parentName);        if (className != null) {            if (classLoader != null) {                // 使用ClassLoader加载Class对象                bd.setBeanClass(ClassUtils.forName(className, classLoader));            } else {                // 设置bean对于的class全名称                bd.setBeanClassName(className);            }        }        return bd;    }

BeanDefinitionReaderUtils的createBeanDefinition方法创建一个GenericBeanDefinition对象,设置此对象的parent名称,以及对应的Class对象或者class全名称。

1.2 解析<bean>标签属性

在parseBeanDefinitionElement方法中调用BeanDefinitionParserDelegate的parseBeanDefinitionAttributes方法处理<bean>标签的属性,parseBeanDefinitionAttributes方法的代码如下。

    public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,            BeanDefinition containingBean, AbstractBeanDefinition bd) {        // spring从4.0开始不再使用singleton属性        if (ele.hasAttribute("singleton")) {            error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);        } else if (ele.hasAttribute("scope")) {            // 设置作用域            bd.setScope(ele.getAttribute("scope"));        } else if (containingBean != null) {            // 嵌套bean,则使用外面那个bean的作用域            bd.setScope(containingBean.getScope());        }        if (ele.hasAttribute("abstract")) {            bd.setAbstract("true".equals(ele.getAttribute("abstract")));        }        String lazyInit = ele.getAttribute("lazy-init");        if ("default".equals(lazyInit)) {            // 默认为false字符串            lazyInit = this.defaults.getLazyInit();        }        bd.setLazyInit("true".equals(lazyInit));        String autowire = ele.getAttribute("autowire");        bd.setAutowireMode(getAutowireMode(autowire));        String dependencyCheck = ele.getAttribute("dependency-check");        bd.setDependencyCheck(getDependencyCheck(dependencyCheck));        if (ele.hasAttribute("depends-on")) {            String dependsOn = ele.getAttribute("depends-on");            bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, ",; "));        }        String autowireCandidate = ele.getAttribute("autowire-candidate");        if ("".equals(autowireCandidate) || "default".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".equals(autowireCandidate));        }        if (ele.hasAttribute("primary")) {            bd.setPrimary("true".equals(ele.getAttribute("primary")));        }        if (ele.hasAttribute("init-method")) {            String initMethodName = ele.getAttribute("init-method");            if (!"".equals(initMethodName)) {                bd.setInitMethodName(initMethodName);            }        } else {            if (this.defaults.getInitMethod() != null) {                bd.setInitMethodName(this.defaults.getInitMethod());                bd.setEnforceInitMethod(false);            }        }        if (ele.hasAttribute("destroy-method")) {            String destroyMethodName = ele.getAttribute("destroy-method");            bd.setDestroyMethodName(destroyMethodName);        } else {            if (this.defaults.getDestroyMethod() != null) {                bd.setDestroyMethodName(this.defaults.getDestroyMethod());                bd.setEnforceDestroyMethod(false);            }        }        if (ele.hasAttribute("factory-method")) {            bd.setFactoryMethodName(ele.getAttribute("factory-method"));        }        if (ele.hasAttribute("factory-bean")) {            bd.setFactoryBeanName(ele.getAttribute("factory-bean"));        }        return bd;    }
    public int getAutowireMode(String attValue) {         String att = attValue;        if("default".equals(attValue)) {            // 根据<beans>标签的default-autowire属性值确定            att = this.defaults.getAutowire();        }        // 不启用自动装配        int autowire = 0;        if("byName".equals(att)) {            // 查找与属性名称相同的bean,并注入            autowire = 1;        } else if("byType".equals(att)) {            // 通过属性的类型查找JavaBean依赖的对象并为其注入            autowire = 2;        } else if("constructor".equals(att)) {            // 同byType一样是通过类型查找依赖对象            // 与byType的区别:它不是使用Seter方法注入,而是使用构造子注入            autowire = 3;        } else if("autodetect".equals(att)) {            // 在byType和constructor之间自动的选择注入方式            autowire = 4;        }        return autowire;    }
    public int getDependencyCheck(String attValue) {        String att = attValue;        if ("default".equals(att)) {            // 根据<beans>标签的default-dependency-check属性值确定            att = this.defaults.getDependencyCheck();        }        if ("all".equals(att)) {            // 检查所有属性            return 3;        } else if ("objects".equals(att)) {            // 检查对象的关联关系            return 1;        } else if ("simple".equals(att)) {            // 检查原始类型和String类型的属性            return 2;        } else {            // 不检查依赖            return 0;        }    }

parseBeanDefinitionAttributes方法主要是解析bean标签上的属性,如果bean标签上有些属性没有设置,则将使用在<beans>标签上对应的属性值。

1.3 解析<meta>标签

在parseBeanDefinitionElement方法中调用BeanDefinitionParserDelegate的parseMetaElements方法处理<bean>标签的子标签<meta>,parseMetaElements方法的源码如下。

    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 metaElement = (Element) node;                String key = metaElement.getAttribute("key");                String value = metaElement.getAttribute("value");                BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);                attribute.setSource(extractSource(metaElement));                attributeAccessor.addMetadataAttribute(attribute);            }        }    }

parseMetaElements方法扫描bean标签下的meta标签,并获取meta标签上的key和value属性值。这里要说明两个方法,其一是isCandidateElement方法,它是判断当前节点是否需要要被处理的节点,代码如下。

    /**    * 判断节点是否是待处理节点    **/    private boolean isCandidateElement(Node node) {        return (node instanceof Element && (isDefaultNamespace(node) || !isDefaultNamespace(node.getParentNode())));    }

具有以下条件中一条的节点是待处理节点。
a. 节点是Element对象,并且在默认命名空间中。
b. 节点是Element对象,且它和它的父节点都不在默认命名空间中。

其二是nodeNameEquals方法,它判断节点的名称是否为指定的字符串,代码如下。

    /**    * 判断节点名称    **/    public boolean nodeNameEquals(Node node, String desiredName) {        return desiredName.equals(node.getNodeName()) || desiredName.equals(getLocalName(node));    }

isCandidateElement和nodeNameEquals方法我们还会在下面的探讨中见到,所以这里对他们都认识一下。

1.4 解析<lookup-method>标签

<lookup-method>标签用于一个无状态bean引用一个有状态bean,也可以这样说一个作用域广的bean引用作用域小的bean,比如singleton bean应用一个prototype bean、sesstion bean、request bean时。

在parseBeanDefinitionElement方法中调用BeanDefinitionParserDelegate的parseLookupOverrideSubElements方法处理<bean>标签的子标签<lookup-method>,parseLookupOverrideSubElements方法的源码如下。

    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 ele = (Element) node;                // 方法名称                String methodName = ele.getAttribute("name");                // 一个bean名称,表示方法需要返回这个名称的bean                String beanRef = ele.getAttribute("bean");                LookupOverride override = new LookupOverride(methodName, beanRef);                override.setSource(extractSource(ele));                overrides.addOverride(override);            }        }    }

1.5 解析<replaced-method>标签

<replaced-method>用于修改非final bean中某个非private且非final方法的实现。一般的,如果一个方法不是只有包范围内访问的的,那么可以直接通过继承来重写方法。但是如果要重写的方法只有包范围内才可以访问的,那么使用replaced-method方法是一个非常不错的选择。

<replaced-method>的作用是重写bean中的某个方法。在parseBeanDefinitionElement方法中调用BeanDefinitionParserDelegate的parseLookupOverrideSubElements方法处理<bean>标签的子标签<replaced-method>,parseReplacedMethodSubElements方法的源码如下。

    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 replacedMethodEle = (Element) node;                // 将被替换的方法名称                String name = replacedMethodEle.getAttribute("name");                // 一个实现了MethodReplacer接口的bean名称                String callback = replacedMethodEle.getAttribute("replacer");                ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);                // 搜索<replaced-method>的<arg-type>子标签                // <arg-type>标签用于指定方法的参数类型                List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, "arg-type");                for (Element argTypeEle : argTypeEles) {                    // 获取<arg-type>的值,这个值表示参数类型的全名称                    String match = argTypeEle.getAttribute("match");                    match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle));                    if (StringUtils.hasText(match)) {                        replaceOverride.addTypeIdentifier(match);                    }                }                replaceOverride.setSource(extractSource(replacedMethodEle));                overrides.addOverride(replaceOverride);            }        }    }

1.6 解析<constructor-arg>标签

<constructor-arg>用于指定使用带参构造器来实例化bean的场景。

在parseBeanDefinitionElement方法中调用BeanDefinitionParserDelegate的parseConstructorArgElements方法处理<bean>标签的子标签<constructor-arg>,parseConstructorArgElements方法的源码如下。

    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")) {                parseConstructorArgElement((Element) node, bd);            }        }    }
    public void parseConstructorArgElement(Element ele, BeanDefinition bd) {        // 获取参数索引        String indexAttr = ele.getAttribute("index");        // 获取参数类型字符串        String typeAttr = ele.getAttribute("type");        // 获取参数名称        String nameAttr = ele.getAttribute("name");        if (StringUtils.hasLength(indexAttr)) {            // 配置了index属性            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));                        // 获取参数值                        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 {            // 没配置index属性            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();            }        }    }

parseConstructorArgElement方法最重要的是通过调用BeanDefinitionParserDelegate的parsePropertyValue方法来获取参数值,parsePropertyValue方法的代码如下。

    public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {        String elementName = (propertyName != null) ?                        "<property> element for property '" + propertyName + "'" :                        "<constructor-arg> element";        // 除了<description>和<meta>标签外,<property>和<constructor-arg>只允许存在一个用于获取属性或参数值的标签,        // 比如ref, value, list, props, set, array, map, bean等        NodeList nl = ele.getChildNodes();        Element subElement = null;        for (int i = 0; i < nl.getLength(); i++) {            Node node = nl.item(i);            if (node instanceof Element && !nodeNameEquals(node, "description") &&                    !nodeNameEquals(node, "meta")) {                // 检查是否有多个值子标签                if (subElement != null) {                    error(elementName + " must not contain more than one sub-element", ele);                } else {                    subElement = (Element) node;                }            }        }        boolean hasRefAttribute = ele.hasAttribute("ref");        boolean hasValueAttribute = ele.hasAttribute("value");        // ref和value属性不能同时设置        // 有了ref或者value属性值,不能再添加值标签        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");            // ref属性不能为空            if (!StringUtils.hasText(refName)) {                error(elementName + " contains empty 'ref' attribute", ele);            }            // 创建并返回RuntimeBeanReference对象            RuntimeBeanReference ref = new RuntimeBeanReference(refName);            ref.setSource(extractSource(ele));            return ref;        } else if (hasValueAttribute) {            // 创建并返回TypedStringValue对象            TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute("value"));            valueHolder.setSource(extractSource(ele));            return valueHolder;        }else if (subElement != null) {            return parsePropertySubElement(subElement, bd);        } else {            // 参数和属性必须要有值            error(elementName + " must specify a ref or value", ele);            return null;        }    }

parsePropertyValue方法主要是处理给定节点元素上的ref和value属性值,如果没有ref或者value属性,则调用BeanDefinitionParserDelegate的parsePropertySubElement方法从<property>、<constroctor-arg>标签的非meta非description子标签中获取值。下面是parsePropertySubElement方法的源代码。

    public Object parsePropertySubElement(Element ele, BeanDefinition bd) {        return parsePropertySubElement(ele, bd, null);    }
    public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {        if (!isDefaultNamespace(ele)) {            // 处理非默认命名空间中的<property>子标签            return parseNestedCustomElement(ele, bd);        } else if (nodeNameEquals(ele, "bean")) {            // 处理<property>下的bean标签            BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);            if (nestedBd != null) {                nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);            }            return nestedBd;        } else if (nodeNameEquals(ele, "ref")) {            // 处理<ref>标签            String refName = ele.getAttribute("bean");            boolean toParent = false;            if (!StringUtils.hasLength(refName)) {                // A reference to the id of another bean in the same XML file.                // 一个bean名称,这个bean来自同一个xml文件                refName = ele.getAttribute("local");                if (!StringUtils.hasLength(refName)) {                    // 一个bean名称,这个bean来自于父类                    refName = ele.getAttribute("parent");                    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;        } else if (nodeNameEquals(ele, "idref")) {            // 处理<idref>标签            return parseIdRefElement(ele);        } else if (nodeNameEquals(ele, "value")) {            // 处理<value>标签            return parseValueElement(ele, defaultValueType);        } else if (nodeNameEquals(ele, "null")) {            // 返回<null>标签代表的null值,并用TypedStringValue对象来包装            TypedStringValue nullHolder = new TypedStringValue(null);            nullHolder.setSource(extractSource(ele));            return nullHolder;        } else if (nodeNameEquals(ele, "array")) {            // 处理<array>标签            return parseArrayElement(ele, bd);        } else if (nodeNameEquals(ele, "list")) {            // 处理<list>标签            return parseListElement(ele, bd);        } else if (nodeNameEquals(ele, "set")) {            // 处理<set>标签            return parseSetElement(ele, bd);        } else if (nodeNameEquals(ele, "map")) {            // 处理<map>标签            return parseMapElement(ele, bd);        } else if (nodeNameEquals(ele, "props")) {            // 处理<props>标签            return parsePropsElement(ele);        } else {            // 值标签必须要提供一个值            error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);            return null;        }    }

parsePropertySubElement方法处理<property>和<constructor-arg>标签下的bean,ref, idref, value, null, array, list, set, map, props以及其他命名空间中的标签,并返回这些标签所代表的值。其中bean、ref和null标签的处理已经这个方法中体现了,下面我们来探讨剩下7个标签如何处理的(这节不会讨论其他命名空间的标签如何处理)。

(1) 处理<idref>标签

<idref>标签不常用,一般只用于注入容器中某个bean的名称或者id。它和<property>的value属性以及<value>标签值一样,只是<idref>的bean、local属性值必须为存在于容器中bean的id或name属性值一致,否则会抛异常。

parsePropertySubElement方法调用BeanDefinitionParserDelegate的parseIdRefElement方法来处理<idref>标签,parseIdRefElement方法代码如下。

    public Object parseIdRefElement(Element ele) {        // 获取bean属性值        String refName = ele.getAttribute("bean");        if (!StringUtils.hasLength(refName)) {            // 获取local属性值,该值与同一个xml文件中某个bean的名称相同            refName = ele.getAttribute("local");            if (!StringUtils.hasLength(refName)) {                error("Either 'bean' or 'local' is required for <idref> element", ele);                return null;            }        }        if (!StringUtils.hasText(refName)) {            error("<idref> element contains empty target attribute", ele);            return null;        }        RuntimeBeanNameReference ref = new RuntimeBeanNameReference(refName);        ref.setSource(extractSource(ele));        return ref;    }

(2) 处理<value>标签

<value>标签用于指定一个字面值,可以是基本类型,字符串。

parsePropertySubElement方法调用BeanDefinitionParserDelegate的parseValueElement方法来处理<value>标签,parseValueElement方法代码如下。

    public Object parseValueElement(Element ele, String defaultTypeName) {        // 获取<value>标签的字面值        String value = DomUtils.getTextValue(ele);        // 获取type属性,表示属性值的类型的全名称        String specifiedTypeName = ele.getAttribute("type");        String typeName = specifiedTypeName;        if (!StringUtils.hasText(typeName)) {            typeName = defaultTypeName;        }        try {            // 根据value值和值类型创建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;        }    }

parseValueElement方法获取<value>标签的字面值和type属性后通过buildTypedStringValue方法创建TypedStringValue 对象,buildTypedStringValue方法的代码如下。

    protected TypedStringValue buildTypedStringValue(String value, String targetTypeName)            throws ClassNotFoundException {        ClassLoader classLoader = this.readerContext.getBeanClassLoader();        TypedStringValue typedValue;        if (!StringUtils.hasText(targetTypeName)) {            typedValue = new TypedStringValue(value);        } else if (classLoader != null) {            // 通过ClassLoader对象来加载一个Class对象            Class<?> targetType = ClassUtils.forName(targetTypeName, classLoader);            typedValue = new TypedStringValue(value, targetType);        } else {            typedValue = new TypedStringValue(value, targetTypeName);        }        return typedValue;    }

(3) 处理<array>标签

<array>标签用于指定一个数组对象。

parsePropertySubElement方法调用BeanDefinitionParserDelegate的parseArrayElement方法来处理<array>标签,parseArrayElement方法代码如下。

    public Object parseArrayElement(Element arrayEle, BeanDefinition bd) {        // 获取元素的value-type属性值,它表示元素的类型        String elementType = arrayEle.getAttribute("value-type");        NodeList nl = arrayEle.getChildNodes();        ManagedArray target = new ManagedArray(elementType, nl.getLength());        target.setSource(extractSource(arrayEle));        target.setElementTypeName(elementType);        // 获取并设置merge属性值        target.setMergeEnabled(parseMergeAttribute(arrayEle));        // 处理子标签        parseCollectionElements(nl, target, bd, elementType);        return target;    }
    /**    * 获取元素的merge属性值    **/    public boolean parseMergeAttribute(Element collectionElement) {        String value = collectionElement.getAttribute("merge");        if ("default".equals(value)) {            value = this.defaults.getMerge();        }        return "true".equals(value);    }

parseArrayElement方法主要是获取<array>标签中的value-type属性值和merge属性值来创建一个实现了Collection接口的ManagedArray对象,然后调用BeanDefinitionParserDelegate中处理集合元素子标签的parseCollectionElements方法,这个方法的源码如下。

    protected void parseCollectionElements(            NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {        for (int i = 0; i < elementNodes.getLength(); i++) {            Node node = elementNodes.item(i);            if (node instanceof Element && !nodeNameEquals(node, "description")) {                // 递归调用parsePropertySubElement方法来解析子节点。                target.add(parsePropertySubElement((Element) node, bd, defaultElementType));            }        }    }

parseCollectionElements方法遍历集合标签(array、set和list)下的子标签,并递归调用处理<property>、<constructor-arg>标签的子标签的parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType)方法。

(4) 处理<list>标签

<list>标签用于指定一个List对象

parsePropertySubElement方法调用BeanDefinitionParserDelegate的parseListElement方法来处理<list>标签,parseListElement方法代码如下。

    public List<Object> parseListElement(Element collectionEle, BeanDefinition bd) {        // 获取元素的value-type属性值,它表示元素的类型        String defaultElementType = collectionEle.getAttribute("value-type");        NodeList nl = collectionEle.getChildNodes();        ManagedList<Object> target = new ManagedList<Object>(nl.getLength());        target.setSource(extractSource(collectionEle));        target.setElementTypeName(defaultElementType);        // 获取并设置merge属性值        target.setMergeEnabled(parseMergeAttribute(collectionEle));        // 处理子标签        parseCollectionElements(nl, target, bd, defaultElementType);        return target;    }

parseListElement方法主要是获取<list>标签中的value-type属性值和merge属性值来创建一个实现了Collection接口的ManagedList对象,然后调用BeanDefinitionParserDelegate中处理集合元素子标签的parseCollectionElements方法。

(5) 处理<set>标签

<set>标签用于指定一个Set对象。

parsePropertySubElement方法调用BeanDefinitionParserDelegate的parseSetElement方法来处理<set>标签,parseSetElement方法代码如下。

    public Set<Object> parseSetElement(Element collectionEle, BeanDefinition bd) {        // 获取元素的value-type属性值,它表示元素的类型        String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);        NodeList nl = collectionEle.getChildNodes();        ManagedSet<Object> target = new ManagedSet<Object>(nl.getLength());        target.setSource(extractSource(collectionEle));        target.setElementTypeName(defaultElementType);        // 获取并设置merge属性值        target.setMergeEnabled(parseMergeAttribute(collectionEle));        // 处理子标签        parseCollectionElements(nl, target, bd, defaultElementType);        return target;    }

parseSetElement方法主要是获取<set>标签中的value-type属性值和merge属性值来创建一个实现了Collection接口的ManagedSet对象,然后调用BeanDefinitionParserDelegate中处理集合元素子标签的parseCollectionElements方法。

(6) 处理<map>标签

<map>标签用于指定一个Map对象。

parsePropertySubElement方法调用BeanDefinitionParserDelegate的parseMapElement方法来处理<map>标签,parseMapElement方法代码如下。

    public Map<Object, Object> parseMapElement(Element mapEle, BeanDefinition bd) {        // 获取Map中key值的类型        String defaultKeyType = mapEle.getAttribute("key-type");        // 获取Map中value值得类型        String defaultValueType = mapEle.getAttribute("value-type");        // 获取<map>标签下的所有<entry>子标签        List<Element> entryEles = DomUtils.getChildElementsByTagName(mapEle, "entry");        ManagedMap<Object, Object> map = new ManagedMap<Object, Object>(entryEles.size());        map.setSource(extractSource(mapEle));        map.setKeyTypeName(defaultKeyType);        map.setValueTypeName(defaultValueType);        // 获取并设置merge属性值        map.setMergeEnabled(parseMergeAttribute(mapEle));        for (Element entryEle : entryEles) {            NodeList entrySubNodes = entryEle.getChildNodes();            Element keyEle = null;            Element valueEle = null;            // 获取<entry>标签下的<key>和值标签            for (int j = 0; j < entrySubNodes.getLength(); j++) {                Node node = entrySubNodes.item(j);                if (node instanceof Element) {                    Element candidateEle = (Element) node;                    if (nodeNameEquals(candidateEle, "key")) {                        // 获取key标签                        if (keyEle != null) {                            error("<entry> element is only allowed to contain one <key> sub-element", entryEle);                        } else {                            keyEle = candidateEle;                        }                    } else {                        // 获取值标签                        if (nodeNameEquals(candidateEle, "description")) {                            // 忽略<description>                        } else if (valueEle != null) {                            error("<entry> element must not contain more than one value sub-element", entryEle);                        } else {                            valueEle = candidateEle;                        }                    }                }            }            // 从<entry>的属性key或者key-ref或者子标签<key>获取Map中元素的key值            Object key = null;            boolean hasKeyAttribute = entryEle.hasAttribute("key");            boolean hasKeyRefAttribute = entryEle.hasAttribute("key-ref");            // 相同意义的标签和属性不能共存            if ((hasKeyAttribute && hasKeyRefAttribute) ||                    ((hasKeyAttribute || hasKeyRefAttribute)) && keyEle != null) {                error("<entry> element is only allowed to contain either " +                        "a 'key' attribute OR a 'key-ref' attribute OR a <key> sub-element", entryEle);            }            if (hasKeyAttribute) {                // 处理属性key值                key = buildTypedStringValueForMap(entryEle.getAttribute("key"), defaultKeyType, entryEle);            } else if (hasKeyRefAttribute) {                // 处理属性key-ref值                String refName = entryEle.getAttribute("key-ref");                if (!StringUtils.hasText(refName)) {                    error("<entry> element contains empty 'key-ref' attribute", entryEle);                }                RuntimeBeanReference ref = new RuntimeBeanReference(refName);                ref.setSource(extractSource(entryEle));                key = ref;            } else if (keyEle != null) {                // 处理<key>标签                key = parseKeyElement(keyEle, bd, defaultKeyType);            } else {                error("<entry> element must specify a key", entryEle);            }            // 从<entry>的属性value或者value-ref或者子值标签(value,array,bean,map等)获取Map中元素的value值            Object value = null;            boolean hasValueAttribute = entryEle.hasAttribute("value");            boolean hasValueRefAttribute = entryEle.hasAttribute("value-ref");            boolean hasValueTypeAttribute = entryEle.hasAttribute("value-type");            // 相同意义的标签和属性不能共存            // value、value-ref、值子标签不能同时存在            if ((hasValueAttribute && hasValueRefAttribute) ||                    ((hasValueAttribute || hasValueRefAttribute)) && valueEle != null) {                error("<entry> element is only allowed to contain either " +                        "'value' attribute OR 'value-ref' attribute OR <value> sub-element", entryEle);            }            // 有value-type属性值,则必须有value属性值,且不能有value-ref值和子值标签            if ((hasValueTypeAttribute && hasValueRefAttribute) ||                (hasValueTypeAttribute && !hasValueAttribute) ||                    (hasValueTypeAttribute && valueEle != null)) {                error("<entry> element is only allowed to contain a 'value-type' " +                        "attribute when it has a 'value' attribute", entryEle);            }            if (hasValueAttribute) {                // 处理value和value-type属性值                String valueType = entryEle.getAttribute("value-type");                if (!StringUtils.hasText(valueType)) {                    valueType = defaultValueType;                }                value = buildTypedStringValueForMap(entryEle.getAttribute("value"), valueType, entryEle);            } else if (hasValueRefAttribute) {                // 处理value-ref属性值                String refName = entryEle.getAttribute("value-ref");                if (!StringUtils.hasText(refName)) {                    error("<entry> element contains empty 'value-ref' attribute", entryEle);                }                RuntimeBeanReference ref = new RuntimeBeanReference(refName);                ref.setSource(extractSource(entryEle));                value = ref;            } else if (valueEle != null) {                // 处理值标签,递归调用parsePropertySubElement方法                value = parsePropertySubElement(valueEle, bd, defaultValueType);            } else {                error("<entry> element must specify a value", entryEle);            }            map.put(key, value);        }        return map;    }
    /**    * 处理<entry>上的属性key或value值。返回一个TypedStringValue对象    **/    protected final Object buildTypedStringValueForMap(String value, String defaultTypeName, Element entryEle) {        try {            // 创建TypedStringValue对象            TypedStringValue typedValue = buildTypedStringValue(value, defaultTypeName);            typedValue.setSource(extractSource(entryEle));            return typedValue;        } catch (ClassNotFoundException ex) {            error("Type class [" + defaultTypeName + "] not found for Map key/value type", entryEle, ex);            return value;        }    }
    /**    * 处理entry标签下的key标签    **/    protected Object parseKeyElement(Element keyEle, BeanDefinition bd, String defaultKeyTypeName) {        NodeList nl = keyEle.getChildNodes();        Element subElement = null;        // 遍历<key>标签下的子标签        for (int i = 0; i < nl.getLength(); i++) {            Node node = nl.item(i);            if (node instanceof Element) {                if (subElement != null) {                    error("<key> element must not contain more than one value sub-element", keyEle);                } else {                    subElement = (Element) node;                }            }        }        return parsePropertySubElement(subElement, bd, defaultKeyTypeName);    }

(7) 处理<props>标签

<props>标签用于指定一个Property对象。

parsePropertySubElement方法调用BeanDefinitionParserDelegate的parsePropsElement方法来处理<props>标签,parsePropsElement方法代码如下。

    public Properties parsePropsElement(Element propsEle) {        ManagedProperties props = new ManagedProperties();        props.setSource(extractSource(propsEle));        props.setMergeEnabled(parseMergeAttribute(propsEle));        // 获取并遍历所有的<prop>标签        List<Element> propEles = DomUtils.getChildElementsByTagName(propsEle, "prop");        for (Element propEle : propEles) {            // 获取<prop>标签的key属性值            String key = propEle.getAttribute("key");            // 以<prop>标签的字面值为value值            String value = DomUtils.getTextValue(propEle).trim();            // 用key值创建TypedStringValue对象            TypedStringValue keyHolder = new TypedStringValue(key);            keyHolder.setSource(extractSource(propEle));            // 用value值创建TypedStringValue            TypedStringValue valueHolder = new TypedStringValue(value);            valueHolder.setSource(extractSource(propEle));            props.put(keyHolder, valueHolder);        }        return props;    }

parsePropsElement方法遍历并获取<props>标签下的所有<prop>标签的key值和字面值。

1.7 解析<property>标签

在parseBeanDefinitionElement方法中调用BeanDefinitionParserDelegate的parsePropertyElements方法处理<bean>标签的子标签<property>,parsePropertyElements方法的源码如下。

    public void parsePropertyElements(Element beanEle, BeanDefinition bd) {        NodeList nl = beanEle.getChildNodes();        for (int i = 0; i < nl.getLength(); i++) {            Node node = nl.item(i);            // 查找<property>标签            if (isCandidateElement(node) && nodeNameEquals(node, "property")) {                parsePropertyElement((Element) node, bd);            }        }    }

parsePropertyElements方法主要是搜索bean标签下的<property>标签,每找到一个<property>标签就调用parsePropertyElement方法来处理此标签,parsePropertyElement方法代码如下。

    public void parsePropertyElement(Element ele, BeanDefinition bd) {        // 获取name属性值,这值必须与bean中的属性名称相同        String propertyName = ele.getAttribute("name");        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对象            PropertyValue pv = new PropertyValue(propertyName, val);            parseMetaElements(ele, pv);            pv.setSource(extractSource(ele));            // 保存PropertyValue对象            bd.getPropertyValues().addPropertyValue(pv);        } finally {            this.parseState.pop();        }    }

和处理<constructor-arg>标签一样,parsePropertyElement方法也是调用BeanDefinitionParserDelegate的parsePropertyValue方法来获取对应的值。

1.8 解析<qualifier>标签

在parseBeanDefinitionElement方法中调用BeanDefinitionParserDelegate的parseQualifierElements方法处理<bean>标签的子标签<qualifier>,parseQualifierElements方法的源码如下。

    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")) {                parseQualifierElement((Element) node, bd);            }        }    }

parseQualifierElements方法主要是搜索并处理<bean>标签下所有的<qualifier>标签,没搜索到一个<qualifier>标签,就会调用BeanDefinitionParserDelegate的parseQualifierElement方法来处理,parseQualifierElement方法的源代码如下。

    /**    * 向BeanDefinition对象中添加AutowireCandidateQualifier对象    **/    public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {        String typeName = ele.getAttribute("type");        // <qualifier>标签必须要有type属性        if (!StringUtils.hasLength(typeName)) {            error("Tag 'qualifier' must have a 'type' attribute", ele);            return;        }        this.parseState.push(new QualifierEntry(typeName));        try {            AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);            qualifier.setSource(extractSource(ele));            // 获取<qualifier>的value属性            String value = ele.getAttribute("value");            if (StringUtils.hasLength(value)) {                qualifier.setAttribute("value", value);            }            NodeList nl = ele.getChildNodes();            // 搜索<attribute>标签            for (int i = 0; i < nl.getLength(); i++) {                Node node = nl.item(i);                if (isCandidateElement(node) && nodeNameEquals(node, "attribute")) {                    Element attributeEle = (Element) node;                    // 获取<attribute>标签的key属性值                    String attributeName = attributeEle.getAttribute("key");                    // 获取<attribute>标签的value属性值                    String attributeValue = attributeEle.getAttribute("value");                    if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) {                        BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);                        attribute.setSource(extractSource(attributeEle));                        qualifier.addMetadataAttribute(attribute);                    } else {                        // 定义了<attribute>标签就必须要提供key和value属性值                        error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);                        return;                    }                }            }            bd.addQualifier(qualifier);        } finally {            this.parseState.pop();        }    }

<qualifier>标签用于给bean创建限制标识符,其中type属性为一个注解类的全名称,spring默认为org.springframework.beans.factory.annotation.Qualifier;value值为bean的标识符,可为空;<attribute>标签的key和value分别表示注解对象的方法名和方法返回值。

<qualifier>作用是区别相同类型的不同bean。个人觉得,它的好处是可以指定一个注解来代表一个bean,以免在代码中hard-code bean的名称,但所指定的注解必须要用@Qualifier注解标注。

qualifier的替代方案:我们可以用id属性值或者name属性值来替代<qualifier>标签。同样可以自定义一个注解类来代表一个bean,只是此时的@Qualifier的value方法的返回值必须与id属性或者name属性对应。本人觉得如果id属性值或者name属性值不会经常改变时,这比使用<qualifier>标签更方便。

2. 装饰BeanDefinition对象


DefaultBeanDefinitionDocumentReader对象的processBeanDefinition方法在调用BeanDefinitionParserDelegate对象的parseBeanDefinitionElement方法解析<bean>标签并获得持有BeanDefintion对象的BeanDefinitionHolder对象后,继续调用BeanDefinitionParserDelegate对象的decorateBeanDefinitionIfRequired来对刚获得BeanDefintion对象做进一步的加工处理。

这一部分的加工处理主要是处理<bean>标签中非默认命名空间中的属性或者子标签,比如p:命名空间修饰的属性。我们来看看BeanDefinitionParserDelegate的decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder)方法代码,如下。

    public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {        return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);    }
    public BeanDefinitionHolder decorateBeanDefinitionIfRequired(            Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {        BeanDefinitionHolder finalDefinition = definitionHolder;        // 首先根据自定义属性装饰BeanDefinition        // 比如http://www.springframework.org/schema/p命名空间的属性        NamedNodeMap attributes = ele.getAttributes();        for (int i = 0; i < attributes.getLength(); i++) {            Node node = attributes.item(i);            finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);        }        // 根据嵌套的自定义标签元素装饰BeanDefinition        NodeList children = ele.getChildNodes();        for (int i = 0; i < children.getLength(); i++) {            Node node = children.item(i);            if (node.getNodeType() == Node.ELEMENT_NODE) {                finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);            }        }        return finalDefinition;    }

这段代码的责任是遍历标签的属性和子节点并调用decorateIfRequired(Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd)方法来处理属性和<bean>的子标签,详见以下代码。

    /**    * 处理自定义命名空间标签来装饰BeanDefinition对象    **/    private BeanDefinitionHolder decorateIfRequired(            Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) {        String namespaceUri = getNamespaceURI(node);        if (!isDefaultNamespace(namespaceUri)) {            // 根据节点所在的命名空间,获取NamespaceHandler对象            // 比如http://www.springframework.org/schema/p命名空间的为SimplePropertyNamespaceHandler            NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);            if (handler != null) {                // 执行装饰BeanDefinition对象                return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));            } else if (namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) {                error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);            } else {                // 节点为自定义命名空间的,但没有指定NamespaceHandler                 if (logger.isDebugEnabled()) {                    logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");                }            }        }        return originalDef;    }

decorateIfRequired方法只处理非默认命名空间的属性和标签,因此它首先会检查节点是否为默认明见中的,是默认空间的则直接返回,如果不是则调用NamespaceHandlerResolver对象(默认为DefaultNamespaceHandlerResolver)来获得节点所在命名空间的处理器NamespaceHandler对象,然后调用NamespaceHandler对象的decorate方法,并返回一个BeanDefinitionHolder 对象,它可以是新创建的,也可以是装饰前的那个。

总结


(1) 可以通过给<beans>指定属性值来全局性的设置<bean>标签对应的属性值,比如定义全局的初始化方法,则可以在<beans>定义default-init-method属性值。

(2)<property>和<constructor-arg>标签使用同一套属性名和子标签。

0 0
原创粉丝点击