spring解析bean标签过程分析

写在前面

本篇在这篇文章基础上继续分析。本篇主要分析的是bean标签的解析过程。

1:作用

没得说,配置spring bean。

2:测试代码

为了方便调试再贴下测试代码:

@Test
public void testBeanDefinitionLoad() {
    // 定义资源
    ClassPathResource classPathResource = new ClassPathResource("testbeandefinition.xml");
    // 定义IOC容器
    DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
    // 定义bean定义读取器
    XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
    // 通过bean定义读取器从资源中读取bean定义
    int i = xmlBeanDefinitionReader.loadBeanDefinitions(classPathResource);
    System.out.println("bean定义的个数是:" + i);
}

xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="testBeanDefinitionBean" class="yudaosourcecode.spring.TestBeanDefinitionBean"/>
    <bean id="testBeanDefinitionBean1" class="yudaosourcecode.spring.TestBeanDefinitionBean"/>
</beans>

然后在org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseDefaultElement处打如下断点,就可以开始调试了:
在这里插入图片描述

3:processBeanDefinition

源码:

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	// <2021-03-01 13:36>
	// 获取持有name和alias的DeanDefinitionHolder实例对象
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	// 获取到了
	if (bdHolder != null) {
		// 进行自定义标签处理,如id,name,class,lazy-init等,不是很影响主流程,先不深究
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			// 注册BeanDefinition
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" +
					bdHolder.getBeanName() + "'", ele, ex);
		}
		// 触发事件
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

<2021-03-01 13:36>处代码参看3.1:parseBeanDefinitionElement

3.1:parseBeanDefinitionElement

源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element)
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
	return parseBeanDefinitionElement(ele, null);
}

继续:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
	// 获取id属性
	String id = ele.getAttribute(ID_ATTRIBUTE);
	// 获取name属性
	String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
	// <2021-03-02 17:47>
	List<String> aliases = new ArrayList<>();
	if (StringUtils.hasLength(nameAttr)) {
		String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
		aliases.addAll(Arrays.asList(nameArr));
	}
	// 默认将id作为bean名称,即id属性的优先级高于name属性
	String beanName = id;
	// 如果是没有设置id,并且设置了name属性,则取第一个作为beanName
	if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
		// 取出并删除第一个作为beanName
		beanName = aliases.remove(0);
		if (logger.isTraceEnabled()) {
			logger.trace("No XML 'id' specified - using '" + beanName +
					"' as bean name and " + aliases + " as aliases");
		}
	}
	// <2021-03-02 17:52>
	if (containingBean == null) {
		checkNameUniqueness(beanName, aliases, ele);
	}
	// <2021-03-02 17:53>
	AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
	// 成功解析出beandefinition
	if (beanDefinition != null) {
		// 本部分是在id和name都没有值的时候,使用默认规则生成bean名称,非重点,可以忽略
		if (!StringUtils.hasText(beanName)) {
			try {
				if (containingBean != null) {
					beanName = BeanDefinitionReaderUtils.generateBeanName(
							beanDefinition, this.readerContext.getRegistry(), true);
				}
				else {
					beanName = this.readerContext.generateBeanName(beanDefinition);
					String beanClassName = beanDefinition.getBeanClassName();
					if (beanClassName != null &&
							beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
							!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
						aliases.add(beanClassName);
					}
				}
				if (logger.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);
		// 使用beandefinition,bean名称,别名数组作为参数构造BeanDefinitionHolder
		return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
	}

	return null;
}

<2021-03-02 17:47>处是使用配置的name属性作为别名,如下配置:

<bean id="testBeanDefinitionBean" class="yudaosourcecode.spring.TestBeanDefinitionBean"
   name="name_1,name_2,name_3"/>

debug结果如下图:
在这里插入图片描述
<2021-03-02 17:52>参考3.2:checkNameUniqueness<2021-03-02 17:53>参看3.3:parseBeanDefinitionElement(ele, beanName, containingBean)

3.2:checkNameUniqueness

源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#checkNameUniqueness
protected void checkNameUniqueness(String beanName, List<String> aliases, Element beanElement) {
	// 已经存在的bean名称
	String foundName = null;
	// 如果是传入的bean名称不为空,并且已使用名称包含,则赋值当前
	// bean名称为已存在bean名称
	if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) {
		foundName = beanName;
	}
	// 如果是从传入的bean名称没有发现,则尝试从别名数组中查找
	if (foundName == null) {
		foundName = CollectionUtils.findFirstMatch(this.usedNames, aliases);
	}
	// 如果是存在,则抛出错误
	if (foundName != null) {
		error("Bean name '" + foundName + "' is already used in this <beans> element", beanElement);
	}
	// 添加传入bean名称到已使用的set集合中
	this.usedNames.add(beanName);
	// 添加所有别名到已使用的set集合中
	this.usedNames.addAll(aliases);
}

3.3:parseBeanDefinitionElement(ele, beanName, containingBean)

源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, java.lang.String, org.springframework.beans.factory.config.BeanDefinition)
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();
	}
	// <2021-03-02 19:01>
	// 设置parent属性
	String parent = null;
	if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
		parent = ele.getAttribute(PARENT_ATTRIBUTE);
	}

	try {
		// <2021-03-02 19:08>
		// 创建用于承载配置信息的beandefinition
		AbstractBeanDefinition bd = createBeanDefinition(className, parent);
		// 解析各种属性
		parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
		// 设置描述
		bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
		/*** 解析bean标签的内部子元素开始 ***/
		// <2021-03-03 14:42>
		// 解析元数据 <meta />
		parseMetaElements(ele, bd);
		// <2021-03-03 14:43>
		// 解析lookup-method
		parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
		// <2021-03-03 14:44>
		// 解析replaced-method
		parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
		// <2021-03-04 18:39>
		// 解析constructor-arg
		parseConstructorArgElements(ele, bd);
		// <2021-03-04 18:42>
		// 解析property
		parsePropertyElements(ele, bd);
		// <2021-03-04 18:43>
		// 解析qualifier
		parseQualifierElements(ele, bd);
		/*** 解析bean标签的内部子元素结束 ***/

		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;
}

<2021-03-02 19:01>设置parent属性,关于parent属性可以参考这里<2021-03-02 19:08>参考3.4:createBeanDefinition<2021-03-03 14:42>处参考4.1:meta子标签解析<2021-03-03 14:43>处参考4.2:lookup-method子标签解析<2021-03-03 14:44>处参考代码replaced-method子标签解析,<2021-03-04 18:39>处参考4.4:constructor-arg子标签解析<2021-03-04 18:42>处参考4.5:property子标签解析<2021-03-04 18:43>处参考4.6:qualifier子标签解析

3.4:createBeanDefinition

BeanDefinition的顶层接口是org.springframework.beans.factory.config.BeanDefinition,该方法返回的是其实现类org.springframework.beans.factory.support.GenericBeanDefinition,看源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#createBeanDefinition
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
			throws ClassNotFoundException {

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

继续:

org.springframework.beans.factory.support.BeanDefinitionReaderUtils#createBeanDefinition
public static AbstractBeanDefinition createBeanDefinition(
			@Nullable String parentName, @Nullable String className, @Nullable 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;
}

直接使用工具类创建了GenericBeanDefinition的实例。

4:bean子标签解析

4.1:meta子标签解析

meta标签只是一种信息补充的方式,不会体现在最终生成的bean对象中。
源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseMetaElements
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
	// 获取当前bean标签的所有子标签,当然后续只处理其中的<meta>子标签
	NodeList nl = ele.getChildNodes();
	for (int i = 0; i < nl.getLength(); i++) {
		Node node = nl.item(i);
		// 这里isCandidateElement判断必须是默认命名空间下的元素,即
		// http://www.springframework.org/schema/beans命名空间
		// nodeNameEquals(node, META_ELEMENT)判断必须是meta标签
		// 也正是本方法要解析的标签
		// 如:<meta key="key1" value="value1"/>
		if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
			// 强转
			Element metaElement = (Element) node;
			// 获取key
			String key = metaElement.getAttribute(KEY_ATTRIBUTE);
			// 获取value
			String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
			// 将key+value封装为BeanMetadataAttribute
			BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
			// extractSource(metaElement)调用的最终是直接return null的,所以可以暂时忽略
			attribute.setSource(extractSource(metaElement));
			// <2021-03-03 15:32>
			attributeAccessor.addMetadataAttribute(attribute);
		}
	}
}

<2021-03-03 15:32>处attributeAccessor的入参的类型为AbstractBeanDefinition,但是其是继承了BeanMetadataAttributeAccessor,如下:

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
		implements BeanDefinition, Cloneable {}

因此具有BeanMetadataAttributeAccessor的能力,addMetadataAttribute源码如下:

org.springframework.beans.BeanMetadataAttributeAccessor#addMetadataAttribute
public void addMetadataAttribute(BeanMetadataAttribute attribute) {
	super.setAttribute(attribute.getName(), attribute);
}

继续:

org.springframework.core.AttributeAccessorSupport#setAttribute
@Override
public void setAttribute(String name, @Nullable Object value) {
	Assert.notNull(name, "Name must not be null");
	if (value != null) {
		// private final Map<String, Object> attributes = new LinkedHashMap<>();
		this.attributes.put(name, value);
	}
	else {
		removeAttribute(name);
	}
}

最终将信息存储到org.springframework.core.AttributeAccessorSupport的map集合中。

4.2:lookup-method子标签解析

关于lookup-method的用法可以参考这里
源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseLookupOverrideSubElements
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
	// 获取子节点
	NodeList nl = beanEle.getChildNodes();
	for (int i = 0; i < nl.getLength(); i++) {
		Node node = nl.item(i);
		if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
			Element ele = (Element) node;
			// name属性就是调用获取bean的方法的名称
			String methodName = ele.getAttribute(NAME_ATTRIBUTE);
			// bean属性就是要返回的bean的bean名称
			String beanRef = ele.getAttribute(BEAN_ELEMENT);
			// 通过方法名称和bean名称构造LookupMethod对象
			LookupOverride override = new LookupOverride(methodName, beanRef);
			override.setSource(extractSource(ele));
			// <2021-03-03 16:59>
			overrides.addOverride(override);
		}
	}
}

<2021-03-03 16:59>是添加lookup-method信息即override到overrides中,overrides是一个存储LookupOverride的容器对象,源码如下:

org.springframework.beans.factory.support.MethodOverrides
public class MethodOverrides {

	private final Set<MethodOverride> overrides = new CopyOnWriteArraySet<>();
}

4.3:replaced-method子标签解析

具体用法可以参看这里
源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseReplacedMethodSubElements
public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
	// 获取bean标签的所有元素
	NodeList nl = beanEle.getChildNodes();
	for (int i = 0; i < nl.getLength(); i++) {
		Node node = nl.item(i);
		/// 默认命名空间下的replaced-method标签才处理
		if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {
			// 强转
			Element replacedMethodEle = (Element) node;
			// 获取要替换的方法名称
			String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
			// 执行具体替换操作的bean名称
			String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
			// 构造ReplaceOverride对象
			ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
			// 获取子元素arg-type,目前不清楚怎么用,用到了再看
			List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT);
			// 循环处理arg-type子标签,处理其中的match属性
			for (Element argTypeEle : argTypeEles) {
				String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE);
				match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle));
				if (StringUtils.hasText(match)) {
					replaceOverride.addTypeIdentifier(match);
				}
			}
			replaceOverride.setSource(extractSource(replacedMethodEle));
			overrides.addOverride(replaceOverride);
		}
	}
}

4.4:constructor-arg子标签解析

这种方式相当于是指派构造函数让spring调用创建对象。
测试使用的xml配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="bookService" class="yudaosourcecode.constructorarg.BookService"/>

    <bean id="studentService" class="yudaosourcecode.constructorarg.StudentService">
        <constructor-arg index="0" value="chenssy"/>
        <constructor-arg name="age" value="100"/>
        <constructor-arg name="bookService" ref="bookService"/>
    </bean>
</beans>

源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseConstructorArgElements
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
	NodeList nl = beanEle.getChildNodes();
	// 遍历所有的标签,如果是默认命名空间下的constructor-arg
	// 则调用parseConstructorArgElement方法处理
	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);
		}
	}
}

我们接着来看parseConstructorArgElement方法源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseConstructorArgElement
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);
			// 判断不小于0
			if (index < 0) {
				error("'index' cannot be lower than 0", ele);
			}
			else {
				try {
					// 存储索引信息到parseState中,其中ConstructorArgumentEntry
					// 代表的是构造函数的参数信息,如参数位置,参数名称,参数类型等
					this.parseState.push(new ConstructorArgumentEntry(index));
					// <2021-03-05 11:19>
					// 解析contructor-arg中的属性,如ref,value等
					// 其实就是获取之后创建bean时获取构造函数参数的值
					Object value = parsePropertyValue(ele, bd, null);
					// 根据value构造构造函数参数的值的对象ConstructorArgumentValues对象信息
					ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
					// 如果有type属性
					if (StringUtils.hasLength(typeAttr)) {
						valueHolder.setType(typeAttr);
					}
					// 如果有name属性
					if (StringUtils.hasLength(nameAttr)) {
						valueHolder.setName(nameAttr);
					}
					valueHolder.setSource(extractSource(ele));
					// 判断存储构造函数索引位置->值 的map中是否已经存在索引位置
					// 如果是存在则异常,即判断是否存在重复的index定义
					if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
						error("Ambiguous constructor-arg entries for index " + index, ele);
					}
					else {
						// 存储构造函数参数索引位置->值 的信息到map中
						bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
					}
				}
				finally {
					this.parseState.pop();
				}
			}
		}
		catch (NumberFormatException ex) {
			error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
		}
	}
	// 没有设置index的情况
	else {
		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));
			// 存储值信息,这里和使用index的情况存储值的方式不一样
			// index方式存储的是位置->值的信息,这存储的是name->值的信息
			bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
		}
		finally {
			this.parseState.pop();
		}
	}
}

<2021-03-05 11:19>处是解析constructor-arg子元素和属性信息,源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertyValue
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
	// 异常时给出提示信息使用
	String elementName = (propertyName != null ?
			"<property> element for property '" + propertyName + "'" :
			"<constructor-arg> element");

	// 给构造函数参数赋值的方式有以下几种
	// 1:ref属性 2:value属性 3:ref子元素 4:value子元素 5:list子元素等
	// 以下主要是判断赋值方式只能有一种,否则会冲突
	NodeList nl = ele.getChildNodes();
	Element subElement = null;
	// 循环遍历constructor-arg的子元素
	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)) {
			// 如果是子元素已经不为空,说明你有多个子元素,这种情况直接异常
			if (subElement != null) {
				error(elementName + " must not contain more than one sub-element", ele);
			}
			// 如果是子元素还没有值,则赋值当前为子元素
			else {
				subElement = (Element) node;
			}
		}
	}
	// 是否有ref属性(给构造函数参数赋值的其中一种方式)
	boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
	// 是否有value属性(给构造函数参数赋值的其中一种方式)
	boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
	// 以下的情况都会导致给构造函数参数赋值的冲突,直接异常
	// 1:同时有ref属性和value属性
	// 2:ref属性和value属性有其一,并且有子元素
	if ((hasRefAttribute && hasValueAttribute) ||
			((hasRefAttribute || hasValueAttribute) && subElement != null)) {
		error(elementName +
				" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
	}
	// 如果是有ref属性
	if (hasRefAttribute) {
		// 获取ref的值
		String refName = ele.getAttribute(REF_ATTRIBUTE);
		// 如果是ref值没有内容则异常
		if (!StringUtils.hasText(refName)) {
			error(elementName + " contains empty 'ref' attribute", ele);
		}
		// 定义RuntimeBeanReference对象,封装ref的值信息
		RuntimeBeanReference ref = new RuntimeBeanReference(refName);
		ref.setSource(extractSource(ele));
		// 返回封装有ref值信息的对象,之后用于给构造函数参数赋值使用
		return ref;
	}
	// 有value属性
	else if (hasValueAttribute) {
		// 封装value的值到TypedStringValue对象中,并返回
		TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
		valueHolder.setSource(extractSource(ele));
		// 返回封装有value信息的对象,之后用于给构造函数参数赋值使用
		return valueHolder;
	}
	// 如果是子元素的情况
	else if (subElement != null) {
		// <2021-03-05 13:24>
		// 进一步解析子元素,获取能够给构造函数参数赋值的对象
		return parsePropertySubElement(subElement, bd);
	}
	else {
		error(elementName + " must specify a ref or value", ele);
		return null;
	}
}

<2021-03-05 13:24>处是处理没有value和ref属性,而是通过子元素给构造函数参数提供值的情况,详细参考4.4.1:parsePropertySubElement

4.4.1:parsePropertySubElement

该方法通过constructor-arg的子标签来解析需要提供给构造函数参数的值,源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertySubElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd) {
	return parsePropertySubElement(ele, bd, null);
}

继续:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertySubElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition, java.lang.String)
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
	// 不是默认的命名空间,一般是
	if (!isDefaultNamespace(ele)) {
		return parseNestedCustomElement(ele, bd);
	}
	// 如果是bean标签,则调用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 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;
	}
	// 如果是idref
	else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
		return parseIdRefElement(ele);
	}
	// 如果是value
	else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
		return parseValueElement(ele, defaultValueType);
	}
	// 如果是null标签,应该是赋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;
	}
}

根据不同的元素类型进行不同的解析,最终结果都是获取到可以给构造函数参数赋值的信息并返回。

4.5:property子标签解析

这种方式spring会通过无参构造函数来创建对象,然后根据property标签的配置调用对应的writter方法,给属性赋值。源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertyElements
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
	// 获取所有的子节点
	NodeList nl = beanEle.getChildNodes();
	// 循环处理所有的默认命名空间下的property元素
	for (int i = 0; i < nl.getLength(); i++) {
		Node node = nl.item(i);
		if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
			// <2021-03-05 15:20>
			// 处理property元素
			parsePropertyElement((Element) node, bd);
		}
	}
}

<2021-03-05 15:20>处源码参考4.5.1:parsePropertyElement

4.5.1:parsePropertyElement

源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertyElement
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 {
		// 判断重复的name值,存在则异常
		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));
		// 存储封装有"属性名称->属性值对象"的对象到beandefinition的
		// 对应数据结构中
		bd.getPropertyValues().addPropertyValue(pv);
	}
	finally {
		this.parseState.pop();
	}
}

4.6:qualifier子标签解析

暂时略。

5:bean自定义标签解析

关于自定义标签可以参考spring的自定义标签
,和spring通过自定义标签干预bean的生成过程

简单回顾下前面的流程,在方法org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition中完成解析bean标签的工作,首先通过如下代码BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);完成解析默认标签的工作,然后接下就是解析自定义标签了,看下源码:

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	// 解析默认标签,返回BeanDefinitionHolder
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	// 如果不为空,解析自定义标签
	if (bdHolder != null) {
		// <2021-03-06 05:50>
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			// 注册处理过默认标签+自定义标签的BeanDefinition
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" +
					bdHolder.getBeanName() + "'", ele, ex);
		}
		// 触发注册完成事件
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

<2021-03-06 05:50>处注册自定义标签,源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinitionHolder)
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef) {
	return decorateBeanDefinitionIfRequired(ele, originalDef, null);
}

继续:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinitionHolder, org.springframework.beans.factory.config.BeanDefinition)
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
			Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
	
	BeanDefinitionHolder finalDefinition = originalDef;

	// 获取所有的属性,循环处理自定义属性
	NamedNodeMap attributes = ele.getAttributes();
	for (int i = 0; i < attributes.getLength(); i++) {
		Node node = attributes.item(i);
		finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
	}

	// 获取所有的子元素,循环处理所有的子元素
	NodeList children = ele.getChildNodes();
	for (int i = 0; i < children.getLength(); i++) {
		Node node = children.item(i);
		if (node.getNodeType() == Node.ELEMENT_NODE) {
			// <2021-03-06 05:53>
			finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
		}
	}
	// 返回🈶经过自定义属性和自定义元素处理后的BeanDefinitionHolder
	return finalDefinition;
}

<2021-03-06 05:53>执行自定义标签的装饰,源码:

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#decorateIfRequired
public BeanDefinitionHolder decorateIfRequired(
			Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
	// 获取命名空间,就是对应的xsd文件中的targetNamespace的值
	String namespaceUri = getNamespaceURI(node);
	// 不是默认命名空间即为自定义命名空间
	if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
		// 通过命名空间获取处理对应标签的NamespaceHandler
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		// 有handler才处理
		if (handler != null) {
			// 调用处理器的decorate方法完成装饰,在该方法中我们可以完成自己的装饰逻辑了,当然这只是其中一种选择
			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;
}

以上解析的自定义标签是作为bean标签的子标签存在的,如果不是作为bean标签的子标签而是和bean标签同级别的标签,这种自定义标签解析还没分析,接下来在spring是如何解析自定义标签的中分析下这种情况。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值