3.1bean标签解析及注册

默认标签解析是在parseDefaultElement中进行的。下面函数功能一目了然,分别对四种标签(import,alias,bean,beans)做不同处理。
DefaultBeanDefinitionDocumentReader
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
    }
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // recurse
        doRegisterBeanDefinitions(ele);
    }
}
在四种标签的解析中,bean标签的解析最为复杂也最重要。所以我们从此标签开始分析,如果理解了此标签的解析过程,其他三种也就迎刃而解了。
 
解析bean标签
DefaultBeanDefinitionDocumentReader
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    //委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法进行元素解析,
    //返回BeanDefinitionHolder类型的实例bdholder,
    //经过这个方法后,bdholder已经包含了配置文件中的配置的各种属性(class、name、id、alias......)
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // Register the final decorated instance.
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                                     bdHolder.getBeanName() + "'", ele, ex);
        }
        // Send registration event.
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}
以上代码大致逻辑:
1)首先委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法对bean标签解析,返回BeanDefinitionHolder类型的实例bdholderBeanDefinitionHolder有三个属性:BeanDefinitionbeanNamealiases),经过这个方法后,bdholder已经包含了bean标签中的配置的各种属性(classnameidalias......
2)当返回的bdholder不为空的情况下并且bean标签下有自定义标签,还需要对自定义标签解析。
3)解析完成后,需要对解析后的bdholder进行注册。委托给BeanDefinitionReaderUtils的regiestBeanDefinition方法(实际执行注册的是BeanDefinitionRegistry的实现类DefaultListable-BeanFactory)
4)最后发出响应事件,通知相关监听器,这个bean已经加载完毕。
下面是时序图:
 

3.1Bean标签的解析及注册

3.1.1解析BeanDefinition(将Xml的Bean标签Element转换为BeanDefinition的实现类GenericBeanDefinition
BeanDefinitionParserDelegate.Java
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return parseBeanDefinitionElement(ele, null);
}

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    //加载id与name属性
    String id = ele.getAttribute(ID_ATTRIBUTE);
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

    //将name属性用,;分割放到集合中
    List<String> aliases = new ArrayList<>();
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        aliases.addAll(Arrays.asList(nameArr));
    }

    //beanName为放入容器中的name
    //默认将id设置为beanname
    //如果id为空,将name属性集合中的第一个设置为beanname
    String beanName = id;
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        beanName = aliases.remove(0);
        if (logger.isTraceEnabled()) {
            logger.trace("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) {
        //如果id属性、name属性都为空
        if (!StringUtils.hasText(beanName)) {
            try {
                //如果id属性、name属性都为空且为内部bean
                //自动生成beanname
                //生成的规则是:
                //1)如果有父类parentName,获取父类parentName+$child+#1...#2(#1,#2为递增)
                //2)如果没有parentName,获取工厂名factoryName+created+#1...#2
                if (containingBean != null) {
                    beanName = BeanDefinitionReaderUtils.generateBeanName(
                        beanDefinition, this.readerContext.getRegistry(), true);
                }
                else {
                    //如果id属性、name属性都为空、不是内部bean
                    //自动生成beanname
                    //生成的规则是:
                    //1)如果有父类parentName,获取父类parentName+$child
                    //2)如果没有parentName,获取工厂名factoryName+created
                    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.isTraceEnabled()) {
                    logger.trace("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;
}
以上代码完成的工作:
1)提取元素中的id和name属性
2)进一步解析其他所有属性并统一封装到GenericBeanDefinition类型的实例中
3)如果监测到bean没有指定beanName,那么使用默认规则为此bean生成beanName
4)将获取到的信息封装到BeanDefinitionHolder实例中
beanName生成规则:
1)将id设置为beanName
2)id为空,将name设置为beanName,name可以有多个,用 ,; 分割
3)如果id,name都为空,自动生成beanName
3.1)如果是内部bean,(初始化的时候是内部bean)
        //生成的规则是:
                //1)如果有父类parentName,获取父类parentName+$child+#1...#2(#1,#2为递增)
                //2)如果没有parentName,获取工厂名factoryName+created+#1...#2
3.2)如果是不是内部bean(区别是没有递增的#1...#2
        //生成的规则是:
                    //1)如果有父类parentName,获取父类parentName+$child
                    //2)如果没有parentName,获取工厂名factoryName+created
 
接下来我们看步骤2中对标签其他属性的解析过程
BeanDefinitionParserDelegate.Java
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的各种属性
        //解析方式:获取ele的节点属性
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

        //以下都是解析bean的子属性
        //解析元数据
        //下面的所有属性的解析方式:获取ele节点的所有子节点childNode进行遍历,判断equals
        parseMetaElements(ele, bd);
        //解析lookup-method属性
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        //解析replaced-method属性
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

        //解析构造函数
        parseConstructorArgElements(ele, bd);
        //解析property子元素
        parsePropertyElements(ele, bd);
        //解析qualifiter子元素
        //Spring允许我们通过Qualifier指定注入Bean的名称,这样歧义就消除了
        parseQualifierElements(ele, bd);

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

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

    return null;
}

 

1.创建用于属性承载的BeanDefinition
BeanDefinition是一个接口,在Spring中存在三种实现:RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition,三个实现都集成了AbstractBean-Definition,其中,Bean是配置文件中<bean>元素标签在容器中的内部表现形式(就是把XML配置中的bean标签抽象成了BeanDefinition对象)。Bean标签与BeanDefinition对象的属性是一一对应的。
BeanDefinitionParserDelegate
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
    throws ClassNotFoundException {

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

BeanDefinitionReaderUtils
public static AbstractBeanDefinition createBeanDefinition(
    @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

    GenericBeanDefinition bd = new GenericBeanDefinition();
    //parentName可能为空
    bd.setParentName(parentName);
    if (className != null) {
        //如果classLoader不为空,则使用以传入的classLoader同一虚拟机加载类对象
        //否则只记录className
        if (classLoader != null) {
            bd.setBeanClass(ClassUtils.forName(className, classLoader));
        }
        else {
            bd.setBeanClassName(className);
        }
    }
    return bd;
}
 
2.解析各种属性
示例:<bean id="" name="" scope="" lazy-init />
解析bean标签上的属性(scope、lazy-init、autowire.....)
BeanDefinitionParserDelegate
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
    @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {

    if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {    //解析singleton属性,但是这个版本已经移除
        error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
    }
    else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {    //解析scope属性
        bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
    }
    else if (containingBean != null) {
        // Take default from containing bean in case of an inner bean definition.
        //在嵌入beanDefinition情况下且没有单独指定scope属性则使用父类默认的属性
        //空和singleton都是单例
        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 (isDefaultValue(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属性
    //用来表示一个bean的实例化依靠另一个bean先实例化,对应bean属性depend-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属性
    //autowire-candidate属性设置为false,这样容器在查找自动装配时,将不考虑该bean。
    //即它不会被考虑作为其他bean自动装配的候选者,但是该bean本身还是可以使用自动装配来注入其他bean
    String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
    if (isDefaultValue(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属性
    //自动装配是当出现多个候选者时,将作为首选者,对应bean属性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;
}
需要注意的是:
scope属性没有指定、scope属性指定singleton,都为单例,也就是说默认是单例。
autowire-candidate属性:默认true。设置为false时,容器在查找自动装配时,将不考虑此bean,即它不会被考虑作为其他bean自动装配的候选者,但是bean本身还是可以使用指定装配来注入其他bean。
primary属性:自动装配出现多个候选者的时候,将作为首选者。
depends-on属性:用来表示一个bean实例化依靠另一个bean先实例化。
factory-bean属性:用于工厂类的类。
factory-method属性:用于调用工厂类的实例化方法。
 
3.解析子元素meta
示例:
<bean id="myTestBean" class="bean.MyTestBean">
    <meta key="testStr" value="aaabb"  />
</bean>
meta是一个额外的声明,当需要使用里面的信息的时候可以通过BeanDefinition的getAttribute(key)方法进行获取。
BeanDefinitionParserDelegate
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
    //获取当前节点的所有子元素
    NodeList nl = ele.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        //提取meta
        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));
            //bd记录信息
            attributeAccessor.addMetadataAttribute(attribute);
        }
    }
}
 
4.解析子元素lookup-method
lookup-method获取器注入。
获取器注入:是一种特殊的方法注入。它是把一个方法声明为返回某种类型的bean,但实际要返回的bean是在配置文件里面配置的。此方法可用在设计有些可插拔功能上,解除程序依赖。
示例:
//创建一个父类
public class User{
    public void showMe(){
        System.out.println("i am user");
    }
}

//创建其子类并覆盖showMe()方法
public class Teacher extend User{ 
    public void showMe(){
           System.out.println("i am teacher");  
    }
}

//创建调用方法
public abstract class GetBeanTest{
    
    public abstract User getBean(){};
    
    public void showMe(){
        this.getBean.showMe();
    }
}

//创建测试方法
public class Main{
    public static void main(String[] args){
        ApplicationContext bf = 
            new ClassPathXmlApplicationContext("test/lookup/lookupTest.xml");
        GetBeanTest test = (GetBeanTest)bf.getBean("getBeanTest");
        test.show();
    }
}

//xml配置
<xml>
    <beans>
        <bean id="getBeanTest" class="GetBeanTest">
            //name为调用方法中的getBean属性
            <lookup-method name="getBean" bean="teacher" />
            //可以插拔替换功能,解除程序依赖。
            //<lookup-method name="geBean" bean="userExt" />
        </bean>
        <bean id="teacher" class="Teacher" />
        <bean id="任何User的实现类 userExt" class="" />
    </beans>
</xml>
BeanDefenitionParserDelegate
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默认bean的子元素下且为<lookup-method />时有效
        if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
            Element ele = (Element) node;
            //获取要修饰的方法
            String methodName = ele.getAttribute(NAME_ATTRIBUTE);
            //获取配置返回的bean
            String beanRef = ele.getAttribute(BEAN_ELEMENT);
            LookupOverride override = new LookupOverride(methodName, beanRef);
            override.setSource(extractSource(ele));
            overrides.addOverride(override);
        }
    }
}

5.解析子元素replaced-method
replace的场景:方法替换。与lookup不同的是,repalced-method不但可以动态替换返回实体bean,而且还能动态地更改原有方法的逻辑。
replace的用法:
//在changeMe中完成某个业务逻辑
public class TestChangeMethod{
    public void changeMe(){
        System.out.println("changeMe");
    }
}

//运营一段时间后,需要改变原有业务逻辑
public class TestMethodReplacer implement MethodReplacer{
    @Override
    public Object reimplement(Object object,Method method,Object[] args)throws Throwable{
        System.out.println("我替换了原有的方法");
        return null;
    }
}

//XML配置
<XML>
    <beans>
        <bean id="testChangeMethod" class="TestChangeMethod">
            //name为方法changeMe()
            <replaced-method name="changeMe" replacer="replacer" />
        </bean>
        <bean id="replacer" class="TestMethodReplacer"></bean>
    </beans>
</XML>
BeanDefinitionParserDelagate
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默认bean的子元素下且为<replace-method时有效
        if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {
            Element replacedMethodEle = (Element) node;
            //提取要替换的方法
            String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
            //提取对应的新的替换方法
            String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
            ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
            // Look for arg-type match elements.
            List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT);
            for (Element argTypeEle : argTypeEles) {
                //记录参数
                String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE);
                match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle));
                if (StringUtils.hasText(match)) {
                    replaceOverride.addTypeIdentifier(match);
                }
            }
            replaceOverride.setSource(extractSource(replacedMethodEle));
            overrides.addOverride(replaceOverride);
        }
    }
}
 
6.解析子元素constructor-arg
constructor-arg示例:
<bean id="helloBean" class="HelloBean">
    <contructor-arg index="0">
        <value>Shing</value>
    </contructor-arg>
    <contructor-arg index="1">
        <value>你好</value>
    </contructor-arg>
</bean>
BeanDefinitionParserDelegate
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);
        }
    }
}

BeanDefinitionParserDelegate
public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
        //提取index属性
        String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
        //提取type属性
        String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
        //提取name属性
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
        if (StringUtils.hasLength(indexAttr)) {
            try {
                int index = Integer.parseInt(indexAttr);
                if (index < 0) {
                    error("'index' cannot be lower than 0", ele);
                }
                else {
                    try {
                        this.parseState.push(new ConstructorArgumentEntry(index));
                        //解析ele对应的属性元素
                        Object value = parsePropertyValue(ele, bd, null);
                        ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
                        if (StringUtils.hasLength(typeAttr)) {
                            valueHolder.setType(typeAttr);
                        }
                        if (StringUtils.hasLength(nameAttr)) {
                            valueHolder.setName(nameAttr);
                        }
                        valueHolder.setSource(extractSource(ele));
                        //不允许重复指定相同参数
                        if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
                            error("Ambiguous constructor-arg entries for index " + index, ele);
                        }
                        else {
                            bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
                        }
                    }
                    finally {
                        this.parseState.pop();
                    }
                }
            }
            catch (NumberFormatException ex) {
                error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
            }
        }
        else {
            //没有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();
            }
        }
    }
上面的代码的逻辑:
  • 如果配置中指定了Index属性
        1.解析contructor-arg的子元素
        2.使用ContructorArgumentValues.ValueHolder类型来封装解析出来的元素
        3.将type、name、index属性封装到ContructorArgumentValues.ValueHolder类型            中,并添加到当前Beandefinition的contructorArgumentValues的indexed-                    ArgumentValue属性中
  • 如果没有指定index属性
       1.解析contructor-arg的子元素
        2.使用ContructorArgumentValues.ValueHolder类型来封装解析出来的元素
        3.将type、name、index属性封装到ContructorArgumentValues.ValueHolder类型            中,并添加到当前Beandefinition的contructorArgumentValues的indexed-                    ArgumentValue属性中
对于是否指定Index属性,Spring的处理流程是一样的,区别在于属性信息保存的位置。
接下里进一步了解解析构造函数配置中子元素的过程parsePropertyValue
//BeanDefinitionParserDelegate
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
    String elementName = (propertyName != null ?
                          "<property> element for property '" + propertyName + "'" :
                          "<constructor-arg> element");

    // Should only have one child element: ref, value, list, etc.
    //一个属性只能对应一种类型ref, value, list, etc.
    NodeList nl = ele.getChildNodes();
    Element subElement = null;
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        //对应description或者meta不处理
        if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
            !nodeNameEquals(node, META_ELEMENT)) {
            // Child element is what we're looking for.
            if (subElement != null) {
                error(elementName + " must not contain more than one sub-element", ele);
            }
            else {
                subElement = (Element) node;
            }
        }
    }

    //解析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)) {
        /**
             * 在constructor-arg上不存在的情况:
             * 1.同时具有ref、value属性
             * 2.存在ref属性或者value属性且又有子元素
             */
        error(elementName +
              " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
    }

    if (hasRefAttribute) {
        //Ref属性的处理,使用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 {
        // Neither child element nor "ref" or "value" attribute found.
        //既没有ref也没有value也没有子元素,Spring蒙圈了
        error(elementName + " must specify a ref or value", ele);
        return null;
    }
}
上面代码的逻辑:
1)略过description或者meta。
2)提取constructor-arg上的ref、value属性,以便根据规则验证正确性,验证其不规范的以下两种情况
  • 同时既有ref属性又有value属性
  • 存在ref属性或者value属性且又有子元素
3)ref属性的处理。<constructor-arg ref="xxx" />
4)value属性的处理。<constructor-arg value="xxx" />
5)子元素的处理。例如
<constructor-arg>
    <map>
        <entry key="key" value="value" />
    </map>
</constructor-arg>
ref属性、value属性、constructor子元素,从左到右权重递减。
解析constructor-arg的子元素parsePropertySubElement
BeanDefinitionParserDelegate
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
    if (!isDefaultNamespace(ele)) {
        return parseNestedCustomElement(ele, bd);
    }
    //解析bean子元素
    else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
        //这里存在嵌套的情况,如果bean-a依赖了bean-b,那么先注册bean-b后在注册bean-a
        BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
        if (nestedBd != null) {
            nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
        }
        return nestedBd;
    }
    //解析ref子元素
    else if (nodeNameEquals(ele, REF_ELEMENT)) {
        // A generic reference to any name of any bean.
        String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
        boolean toParent = false;
        if (!StringUtils.hasLength(refName)) {
            // A reference to the id of another bean in a parent context.
            refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
            toParent = true;
            if (!StringUtils.hasLength(refName)) {
                error("'bean' or 'parent' is required for <ref> element", ele);
                return null;
            }
        }
        if (!StringUtils.hasText(refName)) {
            error("<ref> element contains empty target attribute", ele);
            return null;
        }
        RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
        ref.setSource(extractSource(ele));
        return ref;
    }
    //解析value子元素
    else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
        return parseIdRefElement(ele);
    }
    else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
        return parseValueElement(ele, defaultValueType);
    }
    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;
    }
    else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
        return parseArrayElement(ele, bd);
    }
    else if (nodeNameEquals(ele, LIST_ELEMENT)) {
        return parseListElement(ele, bd);
    }
    else if (nodeNameEquals(ele, SET_ELEMENT)) {
        return parseSetElement(ele, bd);
    }
    else if (nodeNameEquals(ele, MAP_ELEMENT)) {
        return parseMapElement(ele, bd);
    }
    else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
        return parsePropsElement(ele);
    }
    else {
        error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
        return null;
    }
}
这里的解析不看了,感觉解析逻辑都差不多
 
7.解析子元素property
property示例:
<bean id="testproperty" class="TestProperty">
    <property name="testStr" value="aaa" />
</bean>

<bean id="testproperty" class="TestProperty">
    <property name="p">
        <list>
            <value>1</value>
            <value>2</value>
        </list>
    </property>
</bean>
解析过程
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.
* <bean id="test" class="test.TestClass">
*     <property name="p" value="aaa"></property>
* </bean>
* 或者
* <bean id="test">
*     <property name="p">
*         <list>
*             <value>aa</value>
*             <value><bb/value>
*         </list>
*     </property>
* </bean>
*/
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();
    }
}
 
8.解析子元素qualifier
qualifier:Spring允许我们通过Qualifier属性指定注入Bean的名称,这样歧义就消除了。bean的名称,不在是id、name、自动生成(自动生成规则上面有写)
示例:
<bean id="testQualifier" class="TestQualifier">
    //value属性就是指定的bean的名称,不在是id、name、自动生成
    <qualifier type="org.Springframework.beans.factory.annotation.Qualifie" value="qf" />
</bean>
本来打算在接下来的逻辑放在这里的,但是太长了,新开一个文档。





posted @ 2021-01-13 16:53  _Shing  阅读(293)  评论(0)    收藏  举报