Spring源码(2)默认标签的解析

背景

上一篇我们介绍了容器的基本实现,结束时讲到这里进行XML的读取,本篇我们介绍默认标签(主要是bean)的解析

parseBeanDefinitions(root, this.delegate);
    /**
     * Parse the elements at the root level in the document:
     * "import", "alias", "bean".
     * @param root the DOM root element of the document
     */
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    //默认标签
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                           //自定义标签
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

1.对各类型标签进行处理

parseDefaultElement(ele, delegate)

标签的详细解析是在parseDefaultElement中进行的,分别处理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);
        }
    }

2.解析Bean标签

在4种标签解析中,对bean的标签解析最为复杂和重要,所以我们从此标签开始深入分析

1.首先委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法进行元素解析,返回BeanDefinitionHolder类型的实例bdHolder,经过这个方法后,bdHoler实例已经包含了我们配置文件中配置的各种属性了,例如class,name,id,alias之类的属性

delegate.parseBeanDefinitionElement(ele);

2.当返回的bdHolder不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析
delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)

3.解析完成后,需要对解析后的bdHolder进行注册,同样注册操作委托给了BeanDefinitionReaderUtils的registerBeanDefinition方法
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());

4.最后发出响应事件,通知相关监听器,这个bean已经加载完成了
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

    /**
     * Process the given bean element, parsing the bean definition
     * and registering it with the registry.
     */
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
         //解析ele,返回BeanDefinitionHolder类型的实例bdHolder,经过这个方法后bdHolder已经包含了配置文件中的各种属性了,例如class、name、id、alias等属性
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
             //如果返回的bdHolder不为空的情况下,如果存在默认标签下还有自定义属性,还需要再次对自定义属性标签进行解析
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                 //解析完成后,需要堆解析后的bdHolder进行注册,同样,注册操作委托给了BeanDefinitionReaderUtils的registerBeanDefinition方法
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
             //最后发出响应事件,通知相关监听器,这个bean已经加载完成
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

2.1解析Element元素

parseBeanDefinitionElement(Element ele)

这里主要涉及以下几步

1.提取元素中的id以及name属性
2.进一步解析其他所有属性并统一封装至GenericBeanDefinition类型的实例中
3.如果检测到bean没有指定beanName,那么使用默认规则为此Bean生成beanName
4.将获取到的信息封装到BeanDefinitionHolder的实例中

    public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";            

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

         //分割name属性    别名    将nameAttr按照 ,/;分割,全部加入aliases
        List aliases = new ArrayList<>();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }
        //如果id和name都没有维护,就会报错
        //如果检测到bean没有指定beanName,那么使用默认规则为此Bean生成beanName
        String beanName = id;
         //如果beanName为空且别名不为空,beanName取别名数组的第0位,此处将别名数组第0位移除
        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");
            }
        }
        //检验名称唯一性
        if (containingBean == null) {
            checkNameUniqueness(beanName, aliases, ele);
        }

        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {
            if (!StringUtils.hasText(beanName)) {
                try {
                    if (containingBean != null) {
                        beanName = BeanDefinitionReaderUtils.generateBeanName(
                                beanDefinition, this.readerContext.getRegistry(), true);
                    }
                    else {
                        beanName = this.readerContext.generateBeanName(beanDefinition);
                        // Register an alias for the plain bean class name, if still possible,
                        // if the generator returned the class name plus a suffix.
                        // This is expected for Spring 1.2/2.0 backwards compatibility.
                        String beanClassName = beanDefinition.getBeanClassName();
                        if (beanClassName != null &&
                                beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                            aliases.add(beanClassName);
                        }
                    }
                    if (logger.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);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }

        return null;
    }
2.1.1检验名称唯一性
checkNameUniqueness(beanName, aliases, ele);

如果发现benaName已经使用过了,在这里报异常

    /**
     * Validate that the specified bean name and aliases have not been used already
     * within the current level of beans element nesting.
     */
    protected void checkNameUniqueness(String beanName, List aliases, Element beanElement) {
        //发现的名称
        String foundName = null;
        //如果已经使用过
        if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) {
            foundName = beanName;
        }
        //二次查询
        if (foundName == null) {
            foundName = CollectionUtils.findFirstMatch(this.usedNames, aliases);
        }
        //如果发现匹配内容
        if (foundName != null) {
            error("Bean name '" + foundName + "' is already used in this  element", beanElement);
        }
        //通过校验usedNames增加beanName和aliases,再解析下一个bean的时候使用usedNames校验beanName是否重复
        this.usedNames.add(beanName);
        this.usedNames.addAll(aliases);
    }
2.1.2解析标签属性名称
parseBeanDefinitionElement(ele, beanName, containingBean);
    /**
     * Parse the bean definition itself, without regard to name or aliases. May return
     * {@code null} if problems occurred during the parsing of the bean definition.
     */
    @Nullable
    public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, @Nullable BeanDefinition containingBean) {

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

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

        try {
             //创建用于承载属性的AbstractBeanDefinition类型的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());
             //解析replaced-method属性
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            //解析构造函数参数
            parseConstructorArgElements(ele, bd);
             //解析property子元素
            parsePropertyElements(ele, bd);
             //解析qualifier子元素
            parseQualifierElements(ele, bd);

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

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

        return null;
    }

创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition

createBeanDefinition(className, parent);

BeanDefinition是一个接口,在Spring中存在三种实现:RootBeanDefinition,ChildBeanDefinition,GenericDefinition,三种实现均继承AbstractBeanDefinition,其中BeanDefinition是配置文件元素标签在容器中的内部表示形式。

Spring通过BeanDefinition将配置文件中的配置信息转变为容器的内部表示,并注册到BeanDefinitionRegistry中

    /**
     * Create a bean definition for the given class name and parent name.    创建一个针对给定类和父类的bean定义
     * @param className the name of the bean class
     * @param parentName the name of the bean's parent bean
     * @return the newly created bean definition
     * @throws ClassNotFoundException if bean class resolution was attempted but failed
     */
    protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
            throws ClassNotFoundException {

        return BeanDefinitionReaderUtils.createBeanDefinition(
                parentName, className, this.readerContext.getBeanClassLoader());
    }

    /**
     * Create a new GenericBeanDefinition for the given parent name and class name,
     * eagerly loading the bean class if a ClassLoader has been specified.
     * @param parentName the name of the parent bean, if any
     * @param className the name of the bean class, if any
     * @param classLoader the ClassLoader to use for loading bean classes
     * (can be {@code null} to just register bean classes by name)
     * @return the bean definition
     * @throws ClassNotFoundException if the bean class could not be loaded
     */
    public static AbstractBeanDefinition createBeanDefinition(
            @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

        GenericBeanDefinition bd = new GenericBeanDefinition();
        bd.setParentName(parentName);
         //parentName可能为空
        if (className != null) {
             //如果classLoader不为空,则使用已传入的classLoader同一虚拟机加载类对象,否则只是记录className
            if (classLoader != null) {
                bd.setBeanClass(ClassUtils.forName(className, classLoader));
            }
            else {
                bd.setBeanClassName(className);
            }
        }
        return bd;
    }
2.1.2.1解析bean各种属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);

Spring在parseBeanDefinitionAttributes中完成了对bean属性的解析,基本上常用的和不常用的都在这里了

    /**
     * Apply the attributes of the given bean element to the given bean * definition.    将给定bean元素的属性应用于给定bean定义
     * @param ele bean declaration element
     * @param beanName bean name
     * @param containingBean containing bean definition
     * @return a bean definition initialized according to the bean element attributes
     */
    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();
        }
        //没有设置或者设置成其他字符,都是false
        bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

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

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

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

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

         //解析init-method属性
        if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
            String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
            bd.setInitMethodName(initMethodName);
        }
        else if (this.defaults.getInitMethod() != null) {
            bd.setInitMethodName(this.defaults.getInitMethod());
            bd.setEnforceInitMethod(false);
        }
         //解析destroy-method属性
        if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
            String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
            bd.setDestroyMethodName(destroyMethodName);
        }
        else if (this.defaults.getDestroyMethod() != null) {
            bd.setDestroyMethodName(this.defaults.getDestroyMethod());
            bd.setEnforceDestroyMethod(false);
        }
        
         //解析factory-method属性
        if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
            bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
        }
         //解析factory-bean属性
        if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
            bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
        }

        return bd;
    }
2.1.2.2解析子元素meta
parseMetaElements(ele, bd);

子元素只是一个额外的声明,需要使用的时候可以通过BeanDefinition的getAttribute(key)方法进行获取

    public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
        NodeList nl = ele.getChildNodes();
         //获取当前节点的所有子元素
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
             //提取mata
            if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
                Element metaElement = (Element) node;
                String key = metaElement.getAttribute(KEY_ATTRIBUTE);
                String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
                 //使用key和value构造BeanMetadataAttribute
                BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
                attribute.setSource(extractSource(metaElement));
                 //记录信息
                attributeAccessor.addMetadataAttribute(attribute);
            }
        }
    }
2.1.2.3解析子元素lookup-method
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());

lookup-method可以用来实现一些热插拔的功能,动态实现一些方法

    /**
     * Parse lookup-override sub-elements of the given bean element.
     */
    public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
        NodeList nl = beanEle.getChildNodes();
         //获取当前节点所有子元素
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
             //仅当在Spring默认子元素下且为
2.1.2.4解析子元素replaced-method
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

replaced-method可以动态替换原有的方法

    /**
     * Parse replaced-method sub-elements of the given bean element.
     */
    public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
        NodeList nl = beanEle.getChildNodes();
         //获取当前节点所有子元素
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
             //仅当在Spring默认子元素下且为 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));
                 //添加replaceOverride
                overrides.addOverride(replaceOverride);
            }
        }
    }
2.1.2.5解析构造参数函数
parseConstructorArgElements(ele, bd);

处理配置构造函数的情况

    
    
    
        
            soldier
            scientist
            pilot
        
    

首先提取constructor-arg上必要的属性(index,type,name)
如果指定了index属性,操作如下
1.解析Constructor-args的子元素
2.使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素
3.将type、name、index属性一并封装在ConstructorArgmentValues.ValueHolder类型中并添加至当前BeanDefinition的constructorArgumentValues的indexedArgumentValues属性中

如果没有指定index属性,操作步骤如下
1.解析constructor-args的子元素
2.使用ConstructorArgumentValues.ValudHolder类型来封装解析出来的元素
3.将type、name、index属性一并封装在ConstructorArgmentValues.ValueHolder类型中并添加至当前BeanDefinition的constructorArgumentValues的genericArgumentValues属性中

    /**
     * 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)) {
                 //解析构造函数参数
                parseConstructorArgElement((Element) node, bd);
            }
        }
    }


    /**
     * Parse a constructor-arg element.
     */
    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)) {
             //如果有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));
                          //解析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 {
             //没写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();
            }
        }
    }

解析ele对应的属性元素

Object value = parsePropertyValue(ele, bd, null);

构造函数中配置子元素的过程

解析过程
1.略过descripion或者meta
2.提取constructor-arg上的ref和value属性,以便于根据规则验证正确性,其规则为constructor-arg上不存在以下情况

同时既有ref属性又有value属性
存在ref属性或者value属性且又有子元素

3.ref属性的处理,使用RuntimeBeanReference封装对应的rfc名称,如

4.value属性值的处理。使用TypedStringValue封装,如

5.子元素的处理,如


    
        
    


    /**
     * Get the value of a property element. May be a list etc.
     * Also used for constructor arguments, "propertyName" being null in this case.
     */
    @Nullable
    public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
        String elementName = (propertyName != null) ?
                        " element for property '" + propertyName + "'" :
                        " element";

        // Should only have one child element: ref, value, list, etc.
         //一个属性只能对应一种类型:ref、value、list等
         //获取所有子节点
        NodeList nl = ele.getChildNodes();
        Element subElement = null;
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
             //不处理descroption和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;
                }
            }
        }
        //解析constructor-arg上的ref属性
        boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
         //解析constructor-arg上的value属性
        boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
        if ((hasRefAttribute && hasValueAttribute) ||
                ((hasRefAttribute || hasValueAttribute) && subElement != null)) {
             //ref和value都不为空报错,存在ref或者value属性且存在子元素报错
            error(elementName +
                    " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
        }
        //如果存在ref属性
        if (hasRefAttribute) {
             //使用RuntimeBeanReference封装对应的ref名称
            String refName = ele.getAttribute(REF_ATTRIBUTE);
            if (!StringUtils.hasText(refName)) {
                error(elementName + " contains empty 'ref' attribute", ele);
            }
            RuntimeBeanReference ref = new RuntimeBeanReference(refName);
            ref.setSource(extractSource(ele));
            return ref;
        }
        else if (hasValueAttribute) {
             //如果存在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 {
             //没有ref也没有value报错
            // Neither child element nor "ref" or "value" attribute found.
            error(elementName + " must specify a ref or value", ele);
            return null;
        }
    }
2.1.2.6解析子元素Property
parsePropertySubElement(subElement, bd);
    @Nullable
    public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd) {
        return parsePropertySubElement(ele, bd, null);
    }

    /**
     * Parse a value, ref or collection sub-element of a property or
     * constructor-arg element.
     * @param ele subelement of property element; we don't know which yet
     * @param defaultValueType the default type (class name) for any
     * {@code } tag that might be created
     */
    @Nullable
    public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
         //如果不是默认标签,走自定义标签解析
        if (!isDefaultNamespace(ele)) {
            return parseNestedCustomElement(ele, bd);
        }
        else if (nodeNameEquals(ele, BEAN_ELEMENT)) {//如果是bean,解析标签属性名称
            BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
            if (nestedBd != null) {
                  //如果返回的bdHolder不为空的情况下,如果存在默认标签下还有自定义属性,还需要再次对自定义属性标签进行解析
                nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
            }
            return nestedBd;
        }
        else if (nodeNameEquals(ele, REF_ELEMENT)) {//ref属性
            // A generic reference to any name of any bean.
            String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
            boolean toParent = false;
            if (!StringUtils.hasLength(refName)) {
                // A reference to the id of another bean in a parent context.
                 //解析parent
                refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
                toParent = true;
                if (!StringUtils.hasLength(refName)) {
                    error("'bean' or 'parent' is required for  element", ele);
                    return null;
                }
            }
            if (!StringUtils.hasText(refName)) {
                error(" 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;
        }
    }

解析子元素property

parsePropertyElements(ele, bd);

parsePropertyElements函数完成了对property属性的提取,property使用方法如下:

或者


    
        aa
        bb
    

具体的解析过程

提取所有property属性子元素,调用parsePropertyElement处理
将返回值使用PropertyValue进行封装,并记录在BeanDefinition中的propertyValues中

    /**
     * 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();
        }
    }
2.1.2.7解析子元素qualifier
parseQualifierElements(ele, bd);
    /**
     * Parse qualifier sub-elements of the given bean element.
     */
    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);
            }
        }
    }

    /**
     * Parse lookup-override sub-elements of the given bean element.
     */
    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;
                String methodName = ele.getAttribute(NAME_ATTRIBUTE);
                String beanRef = ele.getAttribute(BEAN_ELEMENT);
                LookupOverride override = new LookupOverride(methodName, beanRef);
                override.setSource(extractSource(ele));
                overrides.addOverride(override);
            }
        }
    }

至此完成了XML文档到GenericBeanDefinition的转换,也就是说这时XML所有默认标签配置都可以在GenericBeanDefinition中找到

3.解析默认标签内部的其定义标签

返回org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader的标签解析起始函数 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)

bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

在decorateBeanDefinitionIfRequired中我们可以看到对于程序默认的标签的处理过程其实是略过的,因为默认标签已经被处理完了,这里只对自定义的标签或者说对bean的自定义属性感兴趣

    public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
        return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);
    }

    public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
            Element ele, BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) {

        BeanDefinitionHolder finalDefinition = definitionHolder;
         //遍历所有属性,看看是否存在适用于修饰的属性
        // Decorate based on custom attributes first.
        NamedNodeMap attributes = ele.getAttributes();
        for (int i = 0; i < attributes.getLength(); i++) {
            Node node = attributes.item(i);
            finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
        }
        
        //遍历所有子节点,看看是否存在适用于修饰的属性
        // Decorate based on custom nested elements.
        NodeList children = ele.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node node = children.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
            }
        }
        return finalDefinition;
    }
decorateIfRequired(node, finalDefinition, containingBd)
    public BeanDefinitionHolder decorateIfRequired(
            Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
        //获取自定义标签的命名空间
        String namespaceUri = getNamespaceURI(node);
        //对非默认标签进行修饰
        if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
             //根据命名空间找到对应的处理器
            NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
            if (handler != null) {
                 //进行修饰
                BeanDefinitionHolder decorated =
                        handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
                if (decorated != null) {
                    return decorated;
                }
            }
            else if (namespaceUri.startsWith("http://www.springframework.org/")) {
                error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
            }
            else {
                // A custom namespace, not to be handled by Spring - maybe "xml:...".
                if (logger.isDebugEnabled()) {
                    logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
                }
            }
        }
        return originalDef;
    }

4.注册解析BeanDefinition

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

对于配置文件,解析完成,装饰也完成了,得到的beanDefinition已经满足后续需求了,剩下的就是注册了,解析的beanDefinition会被注册到BeanDefinitionRegistry类型的实例registry中,其中有两部分,通过beanName注册和通过别名注册

    /**
     * Register the given bean definition with the given bean factory.
     * @param definitionHolder the bean definition including name and aliases
     * @param registry the bean factory to register with
     * @throws BeanDefinitionStoreException if registration failed
     */
    public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        // Register bean definition under primary name.
         //使用beanName作为注册唯一标识
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

        // Register aliases for bean name, if any.
         //注册所有别名
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }

4.1通过beanName注册

registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

在对应bean的注册处理方式上,主要进行了几个步骤
1.对于AbstractBeanDefinition的校验,在解析XML文件的时候我们提到过校验,但此校验非彼校验,之前的校验是针对XML文件格式的校验,而此时的校验是对于AbstractBeanDefinition的methodOverrides属性的
2.对于beanName已经注册的情况的处理,如果设置了不允许bean的覆盖,则抛出异常,否则直接覆盖
3.加入map缓存
4.清除之前留下的对于的beanName的缓存

    /** List of bean definition names, in registration order */
    private volatile List beanDefinitionNames = new ArrayList<>(256);    

    //单例模式beanName列表
    /** List of names of manually registered singletons, in registration order */
    private volatile Set manualSingletonNames = new LinkedHashSet<>(16);

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
         //验证BeanName
        Assert.hasText(beanName, "Bean name must not be empty");
         //验证Bean定义
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

         //注册前最后一次校验,这里的校验不同于之前的XML文件校验,
         //主要是对于AbstractBeanDefinition属性中的methodOverrides校验
         //校验methodOverrides是否与工厂方法并存或者methodOverrides对应的方法不存在
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        BeanDefinition oldBeanDefinition;

        oldBeanDefinition = this.beanDefinitionMap.get(beanName);
         //处理已经注册过的beanName情况
        if (oldBeanDefinition != null) {
             //如果对应的beanName已经注册并且在配置中配置了bean不允许被覆盖,则抛出异常
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                        "': There is already [" + oldBeanDefinition + "] bound.");
            }
            else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(oldBeanDefinition)) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
             //注册beanDefinition
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
             //hasBeanCreationStarted 检查该工厂的bean创建阶段是否已经开始
            if (hasBeanCreationStarted()) {//已经开始
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                 // beanDefinitionMap是全局变量,这里存在并发访问的情况
                synchronized (this.beanDefinitionMap) {
                      //注册beanDefinition
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                      //新建已更新的beanDefinition列表,大小为已注册beanDefinitionName列表大小 + 1
                    List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                      //加入所有已注册的beanDefinitionName
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                      //加入本次注册的beanName
                    updatedDefinitions.add(beanName);
                      //更新已注册的beanDefinitionName列表为updatedDefinitions,为什么不直接更新?ArrayList可以动态扩展,但是在插入新的数据并不是申请一个空间,时是直接将现有长度乘以2然后把元素复制过去,所以设置一个合适的长度可以减少空间的浪费
                    this.beanDefinitionNames = updatedDefinitions;
                      //如果单例模式beanName列表包含本次注册的beanName
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                          //就将其移除掉
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
             //该工厂的bean创建阶段没有开始
            else {
                // Still in startup registration phase
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }
         //重置beanName对应的缓存
        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }


    /**
     * 重置所有beanName对应的缓存
     * Reset all bean definition caches for the given bean,
     * including the caches of beans that are derived from it.
     * @param beanName the name of the bean to reset
     */
    protected void resetBeanDefinition(String beanName) {
        // Remove the merged bean definition for the given bean, if already created.
        clearMergedBeanDefinition(beanName);

        // Remove corresponding bean from singleton cache, if any. Shouldn't usually
        // be necessary, rather just meant for overriding a context's default beans
        // (e.g. the default StaticMessageSource in a StaticApplicationContext).
        destroySingleton(beanName);

        // Reset all bean definitions that have the given bean as parent (recursively).
         //重设所有以beanName为父bean的bean的缓存
        for (String bdName : this.beanDefinitionNames) {
            if (!beanName.equals(bdName)) {
                BeanDefinition bd = this.beanDefinitionMap.get(bdName);
                if (beanName.equals(bd.getParentName())) {
                    resetBeanDefinition(bdName);
                }
            }
        }
    }

4.2通过别名注册

registry.registerAlias(beanName, alias);

alias和beanName相同的情况下,如果alias和beanName名称相同就不需要处理,并移除原有alias

alias覆盖处理,若aliasName已经使用并且指向另一个beanName则需要用户的设置进行处理

alias循环检查,当A->B存在时,如果A->C->B出现就抛出异常

注册alias

    @Override
    public void registerAlias(String name, String alias) {
        Assert.hasText(name, "'name' must not be empty");
        Assert.hasText(alias, "'alias' must not be empty");
        synchronized (this.aliasMap) {
             //如果beanName和alias相同的话不记录alias,并删除对应的alias
            if (alias.equals(name)) {
                this.aliasMap.remove(alias);
            }
            else {
                String registeredName = this.aliasMap.get(alias);
                if (registeredName != null) {
                    if (registeredName.equals(name)) {
                        // An existing alias - no need to re-register
                        return;
                    }
                      //如果alias不允许被覆盖
                    if (!allowAliasOverriding()) {
                        throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
                                name + "': It is already registered for name '" + registeredName + "'.");
                    }
                }
                 //校验是否存在循环例如:A->B 存在时,不能出现 A->C->B
                checkForAliasCircle(name, alias);
                 //注册alias
                this.aliasMap.put(alias, name);
            }
        }
    }

5.通知监听器解析以及注册完成

getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   //Spring中并没有对此做逻辑处理,开发人员需要时可以通过注册监听器的方式将处理逻辑写进监听器中 
   protected final XmlReaderContext getReaderContext() {
        Assert.state(this.readerContext != null, "No XmlReaderContext available");
        return this.readerContext;
    }

至此标签解析完成

你可能感兴趣的:(spring)