Spring IOC:parseDefaultElement调用链

参考资料:

《Spring IoC源码学习:parseDefaultElement 详解》

前文:

《Spring IOC:obtainFreshBeanFactory调用链》

写在开头:本文为个人学习笔记,内容比较随意,夹杂个人理解,如有错误,欢迎指正。

目录

一、parseDefaultElement调用链

        1、parseDefaultElement

        2、processBeanDefinition

二、parseBeanDefinitionElement调用链

        1、parseBeanDefinitionElement

        2、 parseBeanDefinitionElement

        3、createBeanDefinition

        4、parseBeanDefinitionAttributes

三、parseConstructorArgElements调用链

        1、parseConstructorArgElements

        2、parseConstructorArgElement

        3、parsePropertyValue

        4、parsePropertySubElement

        5、parseValueElement

        6、buildTypedStringValue

四、parsePropertyElements调用链

        1、parsePropertyElements

        2、parsePropertyElement

五、registerBeanDefinition调用链

        1、registerBeanDefinition

        2、registerBeanDefinition

        补充:

        3、resetBeanDefinition

        4、registerAlias

总结:


一、parseDefaultElement调用链

        1、parseDefaultElement

        在前文中,parseBeanDefinitions方法对于xml配置的bean采用parseDefaultElement方法逐个解析。

public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT;
// public static final String BEAN_ELEMENT = "bean";

public static final String NESTED_BEANS_ELEMENT = "beans";

public static final String ALIAS_ELEMENT = "alias";

public static final String NAME_ATTRIBUTE = "name";

public static final String ALIAS_ATTRIBUTE = "alias";

public static final String IMPORT_ELEMENT = "import";

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    // 1.对import标签的处理
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    // 2.对alias标签的处理
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
    }
    // 3.对bean标签的处理
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    // 4.对beans标签的处理
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // recurse
        doRegisterBeanDefinitions(ele);
    }
}

        2、processBeanDefinition

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 进行节点定义解析, 经过这个方法后,bdHolder会包含一个Bean节点的所有属性,例如name、class、id
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        // 若存在默认标签的子节点下再有自定义属性,需要再次对自定义标签再进行解析(基本不用,不做深入解析)
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // Register the final decorated instance.
            // 解析节点定义完成后,需要对解析后的bdHolder进行注册
            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));
    }
}

二、parseBeanDefinitionElement调用链

        1、parseBeanDefinitionElement

        这一步在获取到<bean>节点后,解析id以及beanName属性,并调用parseBeanDefinitionElement方法封装成beanDefinition 

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return parseBeanDefinitionElement(ele, null);
}
 
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
    // 解析name和id属性
    String id = ele.getAttribute(ID_ATTRIBUTE);
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
 
    // 分割name属性(通过逗号或分号)
    // public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";
    // 例如:<bean name="demoService,demoServiceAlias" class=""/>,分割后aliases为[demoService, demoServiceAlias]
    List<String> aliases = new ArrayList<String>();
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        aliases.addAll(Arrays.asList(nameArr));
    }
 
    // beanName默认使用id
    String beanName = id;
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        // 如果id为空,并且aliases不为空,则取aliases的第一个元素作为beanName,其他的仍作为别名
        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) {
        // 检查beanName和aliases是否在同一个 <beans> 下已经存在
        checkNameUniqueness(beanName, aliases, ele);
    }
 
    // 进一步解析bean的其他所有属性并统一封装至GenericBeanDefinition类型实例中
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
        if (!StringUtils.hasText(beanName)) {
            try {
                // 如果bean定义存在,但是beanName为空,则用Spring默认的生成规则为当前bean生成beanName
                if (containingBean != null) {
                    beanName = BeanDefinitionReaderUtils.generateBeanName(
                            beanDefinition, this.readerContext.getRegistry(), true);
                }
                else {
                    // Spring提供的生成规则生成beanName
                    // 例如:com.joonwhee.open.demo.service.impl.DemoServiceImpl#0
                    beanName = this.readerContext.generateBeanName(beanDefinition);
                    
                    String beanClassName = beanDefinition.getBeanClassName();
                    if (beanClassName != null &&
                            beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                            !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                        // 如果Spring默认的生成规则生成的beanName为:类名加后缀,则将类名注册为别名
                        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);
        // 将bean定义、beanName、bean别名数组封装成BeanDefinitionHolder
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }
 
    return null;
}

        2、 parseBeanDefinitionElement

        上一步获取了当前<bean>的id以及beanName,这里进一步解析该节点的其他属性,首先是class、parent节点。然后我们根据这两个属性创建beanDefinition对象bd,继而解析其余各节点(如constructor-arg、property)并置入bd中

public AbstractBeanDefinition parseBeanDefinitionElement(
        Element ele, String beanName, BeanDefinition containingBean) {
 
    this.parseState.push(new BeanEntry(beanName));
 
    String className = null;
    // 解析class属性
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }
 
    try {
        String parent = null;
        // 解析parent属性
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }
        // 创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);
 
        // 解析bean的各种属性
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        // 提取description
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
        parseMetaElements(ele, bd);
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
 
        // 解析constructor-arg子节点
        parseConstructorArgElements(ele, bd);
        // 解析property子节点
        parsePropertyElements(ele, bd);
        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;
}

        3、createBeanDefinition

        根据className、parentName、beanDefinition、BeanClassLoader利用反射创建对象bd

	// BeanDefinitionParserDelegate.java
    protected AbstractBeanDefinition createBeanDefinition(String className, String parentName)
			throws ClassNotFoundException {

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

    // BeanDefinitionReaderUtils.java
	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) {
				bd.setBeanClass(ClassUtils.forName(className, classLoader));
			}
			else {
				bd.setBeanClassName(className);
			}
		}
		return bd;
	}

        4、parseBeanDefinitionAttributes

        解析本节点中各个属性,并置入bd(AbstractBeanDefinition 对象)中,包括scope、depends-on等(但不包含constructor-arg、property)

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
        BeanDefinition containingBean, AbstractBeanDefinition bd) {
    // 解析singleton属性
    if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
        // singleton属性已经不支持, 如果使用了会直接抛出异常, 请使用scope属性代替
        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属性, 默认为false
    String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
    if (DEFAULT_VALUE.equals(lazyInit)) {
        lazyInit = this.defaults.getLazyInit();
    }
    bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
 
    // 解析autowire属性
    String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
    bd.setAutowireMode(getAutowireMode(autowire));
 
    // 解析dependency-check属性
    String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
    bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
 
    // 解析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);
        if (!"".equals(initMethodName)) {
            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;
}

三、parseConstructorArgElements调用链

        从这一步开始,针对构造方法初始化的bean进行解析

        1、parseConstructorArgElements

        拿到 beanEle的所有子节点,遍历解析所有是constructor-arg节点的子节点。(bean 中必须要有相应的构造函数才可以使用,否则会报错)

public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
    // 拿到beanEle节点的所有子节点
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
            // 解析constructor-arg
            parseConstructorArgElement((Element) node, bd);
        }
    }
}

        2、parseConstructorArgElement

        constructor-arg中index用来指定对应构造方法中的第几个参数。在index存在的情况下,先判断index是否重复指定,如果是则抛出异常;如果不重复,则将 index 和 valueHolder 以 key-value 形式添加至当前BeanDefinition 的 constructorArgumentValues 的 indexedArgumentValues 属性中(用于前面判断index是否重复指定)
        无论是否存在index,我们都会先调用parsePropertyValue方法对该constructor-arg节点进行进一步的解析。

public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
    // 获取基础属性index、type、name等属性
    String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
    String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
    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 {
                    // index不为空的处理
                    this.parseState.push(new ConstructorArgumentEntry(index));
                    // 解析ele节点对应的属性值
                    Object value = parsePropertyValue(ele, bd, null);
                    // 使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素
                    ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
                    // 将type属性封装到ConstructorArgumentValues.ValueHolder
                    if (StringUtils.hasLength(typeAttr)) {
                        valueHolder.setType(typeAttr);
                    }
                    // 将name属性封装到ConstructorArgumentValues.ValueHolder
                    if (StringUtils.hasLength(nameAttr)) {
                        valueHolder.setName(nameAttr);
                    }
                    valueHolder.setSource(extractSource(ele));
                    // 判断index是否重复指定, 如果是则抛出异常
                    if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
                        error("Ambiguous constructor-arg entries for index " + index, ele);
                    }
                    else {
                        // 将index和valueHolder以key-value形式添加至当前BeanDefinition的constructorArgumentValues
                        // 的indexedArgumentValues属性中,(用于上面判断index是否重复指定)
                        bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
                    }
                }
                finally {
                    this.parseState.pop();
                }
            }
        }
        catch (NumberFormatException ex) {
            error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
        }
    }
    else {
        try {
            // index为空的处理
            this.parseState.push(new ConstructorArgumentEntry());
            // 解析ele节点对应的属性值
            Object value = parsePropertyValue(ele, bd, null);
            // 使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素
            ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
            // 将type属性封装到ConstructorArgumentValues.ValueHolder
            if (StringUtils.hasLength(typeAttr)) {
                valueHolder.setType(typeAttr);
            }
            // 将name属性封装到ConstructorArgumentValues.ValueHolder
            if (StringUtils.hasLength(nameAttr)) {
                valueHolder.setName(nameAttr);
            }
            valueHolder.setSource(extractSource(ele));
            // 将valueHolder添加至当前BeanDefinition的constructorArgumentValues的genericArgumentValues属性中
            // 与上面的indexedArgumentValues类似,上面有index存为map,这边没index存为list
            bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
        }
        finally {
            this.parseState.pop();
        }
    }
}

        3、parsePropertyValue

        constructor-arg节点赋值可以直接使用value,或这ref调用其他已创建对象,还可以使用子节点(只可以有1个,子节点可用于实例化list、map等对象),对应着三种不同的赋值方式,分别有三套逻辑进行解析。子节点解析方法parsePropertySubElement同样包含针对ref、value的处理方法。

public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
    String elementName = (propertyName != null) ?
            "<property> element for property '" + propertyName + "'" :
            "<constructor-arg> element";
 
    // Should only have one child element: ref, value, list, etc.
    // 拿到ele节点的子节点,例如list、map
    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) {
                // 只能有1个子节点,否则抛出异常
                error(elementName + " must not contain more than one sub-element", ele);
            } else {
                // 找到子节点,赋值给subElement
                subElement = (Element) node;
            }
        }
    }
 
    // 解析constructor-arg上的ref属性
    boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
    // 解析constructor-arg上的value属性
    boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
    // 合法性校验。在constructor-arg上:ref属性、value属性、子节点,三者只能有1个,因为这三个都是用来表示该节点的值。
    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) {
        // ref属性的处理,使用RuntimeBeanReference封装对应的ref值(该ref值指向另一个bean的beanName),
        // RuntimeBeanReference起到占位符的作用,ref指向的beanName将在运行时被解析成真正的bean实例引用
        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属性,也没有子节点,没法获取ele节点的值,直接抛异常
        // Neither child element nor "ref" or "value" attribute found.
        error(elementName + " must specify a ref or value", ele);
        return null;
    }
}

        4、parsePropertySubElement

         调用parsePropertySubElement方法对子节点中各节点进行解析,其中parseValueElement方法解析value节点最常用。

public Object parsePropertySubElement(Element ele, BeanDefinition bd) {
    return parsePropertySubElement(ele, bd, null);
}
 
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
    // 校验是否为默认的命名空间,如果不是则走解析自定义节点代码
    if (!isDefaultNamespace(ele)) {
        return parseNestedCustomElement(ele, bd);
    }
    // 解析bean节点
    else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
        BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
        if (nestedBd != null) {
            nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
        }
        return nestedBd;
    }
    // 解析ref节点
    else if (nodeNameEquals(ele, REF_ELEMENT)) {
        // A generic reference to any name of any bean.
        String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
        boolean toParent = false;
        if (!StringUtils.hasLength(refName)) {
            // A reference to the id of another bean in the same XML file.
            refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
            if (!StringUtils.hasLength(refName)) {
                // A reference to the id of another bean in a parent context.
                refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
                toParent = true;
                if (!StringUtils.hasLength(refName)) {
                    error("'bean', 'local' or 'parent' is required for <ref> element", ele);
                    return null;
                }
            }
        }
        if (!StringUtils.hasText(refName)) {
            error("<ref> element contains empty target attribute", ele);
            return null;
        }
        RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
        ref.setSource(extractSource(ele));
        return ref;
    }
    // 解析idref节点
    else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
        return parseIdRefElement(ele);
    }
    // 解析value节点
    else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
        return parseValueElement(ele, defaultValueType);
    }
    // 解析null节点
    else if (nodeNameEquals(ele, NULL_ELEMENT)) {
        // It's a distinguished null value. Let's wrap it in a TypedStringValue
        // object in order to preserve the source location.
        TypedStringValue nullHolder = new TypedStringValue(null);
        nullHolder.setSource(extractSource(ele));
        return nullHolder;
    }
    // 解析array节点
    else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
        return parseArrayElement(ele, bd);
    }
    // 解析list节点
    else if (nodeNameEquals(ele, LIST_ELEMENT)) {
        return parseListElement(ele, bd);
    }
    // 解析set节点
    else if (nodeNameEquals(ele, SET_ELEMENT)) {
        return parseSetElement(ele, bd);
    }
    // 解析map节点
    else if (nodeNameEquals(ele, MAP_ELEMENT)) {
        return parseMapElement(ele, bd);
    }
    // 解析props节点
    else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
        return parsePropsElement(ele);
    }
    else {
        // 未知属性,抛异常
        error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
        return null;
    }
}

        5、parseValueElement

        解析value节点(最常用)

public Object parseValueElement(Element ele, String defaultTypeName) {
    // It's a literal value.
    // 拿到ele节点值
    String value = DomUtils.getTextValue(ele);
    // 拿到ele节点的type属性
    String specifiedTypeName = ele.getAttribute(TYPE_ATTRIBUTE);
    String typeName = specifiedTypeName;
    if (!StringUtils.hasText(typeName)) {
        // ele节点没有type属性则则使用入参defaultTypeName
        typeName = defaultTypeName;
    }
    try {
        // 使用value和type构建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;
    }
}

        6、buildTypedStringValue

        使用 value 和 typeName 构建 TypedStringValue

protected TypedStringValue buildTypedStringValue(String value, String targetTypeName)
        throws ClassNotFoundException {
 
    ClassLoader classLoader = this.readerContext.getBeanClassLoader();
    TypedStringValue typedValue;
    // targetTypeName为空,则只使用value来构建TypedStringValue
    if (!StringUtils.hasText(targetTypeName)) {
        typedValue = new TypedStringValue(value);
    }
    // targetTypeName不为空,并且classLoader不为null
    else if (classLoader != null) {
        // 利用反射,构建出type的Class,如果type是基本类型,或者 java.lang 包下的常用类,
        // 可以直接从缓存(primitiveTypeNameMap、commonClassCache)中获取
        Class<?> targetType = ClassUtils.forName(targetTypeName, classLoader);
        typedValue = new TypedStringValue(value, targetType);
    } else {
        typedValue = new TypedStringValue(value, targetTypeName);
    }
    return typedValue;
}

四、parsePropertyElements调用链

        1、parsePropertyElements

        和上文中解析constructor-arg节点一样,遍历解析beanEle节点的所有子节点找出直接使用property赋值的节点。(property节点调用set方法赋值,因此bean中的属性必须要有set方法才可以使用,否则会报错)

public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
    // 拿到beanEle节点的所有子节点
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
            // 解析property节点
            parsePropertyElement((Element) node, bd);
        }
    }
}

        2、parsePropertyElement

        依旧和构造方法注册一致,调用parsePropertyValue方法解析节点。不过这里不用再判断index节点了。

public void parsePropertyElement(Element ele, BeanDefinition bd) {
    // 拿到name属性
    String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
    if (!StringUtils.hasLength(propertyName)) {
        // name属性为必要属性,如果没有配置,则抛出异常
        error("Tag 'property' must have a 'name' attribute", ele);
        return;
    }
    this.parseState.push(new PropertyEntry(propertyName));
    try {
        // 校验在相同bean节点下,是否存在相同的name属性,如果存在则抛出异常
        if (bd.getPropertyValues().contains(propertyName)) {
            error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
            return;
        }
        // 解析属性值
        Object val = parsePropertyValue(ele, bd, propertyName);
        // 将解析的属性值和属性name封装成PropertyValue
        PropertyValue pv = new PropertyValue(propertyName, val);
        // 解析meta节点(基本不用,不深入解析)
        parseMetaElements(ele, pv);
        pv.setSource(extractSource(ele));
        // 将解析出来的PropertyValue,添加到BeanDefinition的propertyValues属性中(上面的重复校验用到)
        bd.getPropertyValues().addPropertyValue(pv);
    }
    finally {
        this.parseState.pop();
    }
}

五、registerBeanDefinition调用链

        在前文中,我们已经得到了beanDefinition、beanName、aliasesArray这三个对象,继而创建了BeanDefinitionHolder对象,然后就可以开始注册操作了。

        1、registerBeanDefinition

        首先调用registerBeanDefinition方法将beanName、BeanDefinition 到缓存中。然后如果有别名,则调用registerAlias方法注册 bean 的 beanName 和对应的别名映射到 aliasMap 缓存中。

public static void registerBeanDefinition(
        BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
        throws BeanDefinitionStoreException {
 
    // 拿到beanName
    String beanName = definitionHolder.getBeanName();
    // 注册beanName、BeanDefinition到缓存中(核心逻辑),实现类为; DefaultListableBeanFactory
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
 
    // 注册bean名称的别名(如果有的话)
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            // 3.注册bean的beanName和对应的别名映射到缓存中(缓存:aliasMap)
            registry.registerAlias(beanName, alias);
        }
    }
}

        2、registerBeanDefinition

        将 beanName 添加到 beanDefinitionNames 缓存,将 beanName 和 BeanDefinition 的映射关系添加到beanDefinitionMap 缓存。

        如果 beanName不重复,对于我们当前正在解析的 obtainFreshBeanFactory 方法来说,因为 bean 创建还未开始,因此进行缓存的注册。

        如果 beanName 重复,并且该 beanName 已经存在单例对象,则会调用 resetBeanDefinition 方法。

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {
    // beanName和beanDefinition为空校验
    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");
 
    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;
 
    // 首先根据beanName从beanDefinitionMap缓存中尝试获取
    oldBeanDefinition = this.beanDefinitionMap.get(beanName);
    if (oldBeanDefinition != null) {
        // beanName存在于缓存中
        if (!isAllowBeanDefinitionOverriding()) {
            // 如果不允许相同beanName重新注册,则直接抛出异常
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                    "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                            "': There is already [" + oldBeanDefinition + "] bound.");
        }

            // logs,此处代码省略
        }
        // 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存(以供后续创建bean时使用)
        this.beanDefinitionMap.put(beanName, beanDefinition);
    } else {
        // beanName不存在于缓存中
        if (hasBeanCreationStarted()) {
            // bean创建阶段已经开始
            // Cannot modify startup-time collection elements anymore (for stable iteration)
            synchronized (this.beanDefinitionMap) {
                // 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存
                this.beanDefinitionMap.put(beanName, beanDefinition);
                // 将本次传进来的beanName 加入beanDefinitionNames缓存
                List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                // 将beanName从manualSingletonNames缓存移除
                if (this.manualSingletonNames.contains(beanName)) {
                    Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
                    updatedSingletons.remove(beanName);
                    this.manualSingletonNames = updatedSingletons;
                }
            }
        } else {
            // bean创建阶段还未开始
            // Still in startup registration phase
            // 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存
            this.beanDefinitionMap.put(beanName, beanDefinition);
            // 将本次传进来的beanName 加入beanDefinitionNames缓存
            this.beanDefinitionNames.add(beanName);
            // 将beanName从manualSingletonNames缓存移除
            this.manualSingletonNames.remove(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }
 
    // 如果存在相同beanName的BeanDefinition,并且beanName已经存在单例对象,则将该beanName对应的缓存信息、单例对象清除,
    // 因为这些对象都是通过oldBeanDefinition创建出来的,需要被覆盖掉的,
    // 我们需要用新的BeanDefinition(也就是本次传进来的beanDefinition)来创建这些缓存和单例对象
    if (oldBeanDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
}

        补充:

        1、hasBeanCreationStarted()这是做什么的?为什么这种情况下需要加锁?

​         这里主要是判断是不是已经有bean被创建,正常来说到目前为止,我们并有创建任何的bean,到现在我们做的仅仅是解析配置,并注册beanDefinition,如果有bean被创建意味着着我们已经开始利用容器去进行我们的业务操作了。此时,Spring容器无法保证使用者是在线程安全的情况下调用了(即我们的业务操作可能会去直接新建bean的操作),也就是无法保证下面的代码不会出现线程安全问题,所以需要加锁。

        2、为什么要将this.beanDefinitionMap.put(beanName, beanDefinition)也放入同步代码块中?

        我们之前已经知道了beanDefinitionNames是要按照注册顺序保存的,所以必须要将put操作也进行同步,不然可能出现顺序错误。

        3、为什么在加锁后给集合中添加元素还要进行一次类似于复制的操作(addAll)?

        我们在业务操作过程中,很可能调用Spring的某些方法,这些方法需要遍历beanDefinitionNames,这些遍历方法通常都是使用迭代器的,我们知道迭代过程中如果我们又对集合进行了添加,移除的操作,会引发快速失败机制如果对快速失败机制不熟悉的请自行百度。为了避免这种情况所以选择新建一个集合然后进行复制。

        3、resetBeanDefinition

        将该beanName的mergedBeanDefinitions 缓存信息删除,将单例缓存删除的该beanName删除。如果存在子 bean 定义,则递归重置。

protected void resetBeanDefinition(String beanName) {
    // 删除beanName的mergedBeanDefinitions缓存(如果有的话)
    clearMergedBeanDefinition(beanName);
    // 从单例缓存中删除该beanName对应的bean(如果有的话)
    destroySingleton(beanName);
    // 重置beanName的所有子Bean定义(递归)
    for (String bdName : this.beanDefinitionNames) {
        if (!beanName.equals(bdName)) {
            BeanDefinition bd = this.beanDefinitionMap.get(bdName);
            // 当前遍历的BeanDefinition的parentName为beanName,则递归调用resetBeanDefinition进行重置
            if (beanName.equals(bd.getParentName())) {
                resetBeanDefinition(bdName);
            }
        }
    }
}

        4、registerAlias

        比较简单,将别名和 beanName 注册到 aliasMap 缓存。

@Override
public void registerAlias(String name, String alias) {
    Assert.hasText(name, "'name' must not be empty");
    Assert.hasText(alias, "'alias' must not be empty");
    // 如果别名和beanName相同,则不算别名,从aliasMap缓存中移除
    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;
            }
            // 如果存在相同的别名,并且不允许别名覆盖,则抛出异常
            if (!allowAliasOverriding()) {
                throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
                        name + "': It is already registered for name '" + registeredName + "'.");
            }
        }
        // 检查name和alias是否存在循环引用。例如A的别名为B,B的别名为A
        checkForAliasCircle(name, alias);
        // 将别名和beanName的映射放到aliasMap缓存中
        this.aliasMap.put(alias, name);
    }
}

总结:

        1、对于传入parseDefaultElement方法的节点调用parseBeanDefinitionElement方法创建AbstractBeanDefinition对象beanDefinition,并将该节点的各类信息解析、存入beanDefinition对象中。

        2、将beanDefinition、beanName、aliasesArray构建成 BeanDefinitionHolder对象并返回,为后续注册做准备。

        3、将 BeanDefinition 和 beanName注册到BeanFactory的缓存中,即beanDefinitionNames (存储beanName集合,类型为ArrayList),以及beanDefinitionMap(beanName和BeanDefinition映射,类型为ConcurrentHashMap)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值