spring源码:bean标签的解析之简单子元素的解析

一、整体脉络

  Spring中每个bean实例,都有一个对应的BeanDefinition实例。这个BeanDefinition实例记录了该bean的各种属性信息,如id、scope等等。先来看一份xml中bean标签的配置

    <bean id="person" class="com.kaka.spring.beans.Person">
        <property name="age" value="22"/>
    </bean>

要把上面的bean标签中的内容,解析为一个BeanDefinition对象,spring做了三个步骤:

  1. 创建BeanDefinition实例
  2. 解析bean标签上的属性,并存储到BeanDefinition实例中
  3. 解析bean标签的子元素,并存储到BeanDefinition实例中
    本章主要分析第3个步骤,bean标签有六个子元素:meta、lookup-method、replaced-method、constructor-arg、property、qualifier;本章分析除constructor-arg之外的其他五个子元素,constructor-arg子元素较为复杂,后面会单独写一篇文章解析。

二、相关类、方法

  • org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions:解析xml的入口,该方法循环解析beans标签的各个子元素,如bean、import等
  • org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition:处理beanDefinition的整体过程,包含bean标签的解析、注册、通知监听器等。
  • org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, java.lang.String, org.springframework.beans.factory.config.BeanDefinition):解析bean标签中的属性子元素

三、源码分析

解析bean标签的整体过程,在BeanDefinitionParserDelegate这个类的parseBeanDefinitionElement()方法中,先来看下代码

	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 {
			// 1.创建用于承载属性的 AbstractBeanDefinition 类型的 GenericBeanDefinition,点进去
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);

			// 2.硬编码解析默认bean的各种属性
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

			// 3.解析子元素
			// 3.1 解析元数据
			parseMetaElements(ele, bd);
			// 3.2 解析lookup-method 属性
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			// 3.3 解析replaced-method 属性
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

			// 3.4 解析构造函数参数
			parseConstructorArgElements(ele, bd);
			// 3.5 解析property子元素
			parsePropertyElements(ele, bd);
			// 3.6 解析qualifier子元素
			parseQualifierElements(ele, bd);

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

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

		return null;
	}
  1. 解析元数据

1.1 源码分析

	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);
				// 使用meta元素的key和value构造BeanMetadataAttribute 对象
				BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
				attribute.setSource(extractSource(metaElement));
				// 把该attribute保存到AttributeAccessorSupport的attributes(是一个LinkedHashMap)属性中
				attributeAccessor.addMetadataAttribute(attribute);
			}
		}
	}

1.2 使用方法
在bean标签中增加meta标签

    <bean id="metaPerson" class="com.kaka.spring.pojo.Person">
        <property name="age" value="22"/>
        <meta key="myMeta" value="元数据"/>
    </bean>

代码使用

    @Before
    public void initFactory(){
        Resource classPathResource = new ClassPathResource("applicationContext.xml");
        xmlBeanFactory = new XmlBeanFactory(classPathResource);
    }

    @Test
    public void metaDataTest(){
        BeanDefinition beanDefinition = ((XmlBeanFactory) xmlBeanFactory).getBeanDefinition("metaPerson");
        // 通过getAttribute()方法就能获取到xml中meta标签中的值
        Object myMeta = beanDefinition.getAttribute("myMeta");
        System.out.println(myMeta);
    }
  1. 解析lookup-method 属性

2.1 源码分析

	public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
		NodeList nl = beanEle.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
				Element ele = (Element) node;
				String methodName = ele.getAttribute(NAME_ATTRIBUTE);
				String beanRef = ele.getAttribute(BEAN_ELEMENT);
				LookupOverride override = new LookupOverride(methodName, beanRef);
				override.setSource(extractSource(ele));
				// 把override实例存入AbstractBeanDefinition的methodOverrides属性中
				overrides.addOverride(override);
			}
		}
	}

2.2 使用方法
lookup-method标签的作用:一个A类型的bean中的某个方法的方法声明,返回值为B类型的bean,lookup-method标签就可以修饰该方法,来指定该方法的返回值为容器中某个B类型的bean。(AB可以是同一个类型)
2.2.1 声明一个接口和两个实现类

public interface Animal {
    void say();
}

public class Cat implements Animal {
    @Override
    public void say() {
        System.out.println("喵喵...");
    }
}

public class Dog implements Animal {
    @Override
    public void say() {
        System.out.println("汪汪");
    }
}

2.2.3 声明一个类,该类包含一个方法声明的返回值为Animal

public abstract class AbstractMethodBean {
	// xml中使用lookup-method标签修饰该方法
    public abstract Animal getAnimalBean();

    public void printSay() {
        getAnimalBean().say();
    }

}

2.2.4 配置文件声明lookup-method标签

    <bean id="cat" class="com.kaka.spring.pojo.Cat"/>

    <bean id="abstractMethodBean" class="com.kaka.spring.pojo.AbstractMethodBean">
        <lookup-method name="getAnimalBean" bean="cat"/>
    </bean>

此时abstractMethodBean这个bean的getAnimalBean()方法的返回值为cat实例;如需修改为dog,修改lookup-method标签中的bean属性值指向容器中的dog即可。

  1. 解析replaced-method 属性

3.1 源码分析

	public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
		NodeList nl = beanEle.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {
				Element replacedMethodEle = (Element) node;
				// 获取要替换的方法名
				String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
				// 获取MethodReplacer类型的bean
				String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
				// 创建replaceOverride 实例
				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));
				// 把replaceOverride实例存入AbstractBeanDefinition的methodOverrides属性中
				overrides.addOverride(replaceOverride);
			}
		}
	}

3.2 使用方法
3.2.1 创建一个MethodReplacer 类型的类和一个Dog普通类

public class ReplaceMethodBean implements MethodReplacer {
    @Override
    public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
        System.out.println("我是一个汪星人...");
        return null;
    }
}

public class Dog implements Animal {
    @Override
    public void say() {
        System.out.println("汪汪");
    }
}

3.2.2 xml配置修改dog类中的say方法,当调用dog的say()方法时,就回转到replaceMethodBean的reimplement()方法。

    <bean id="replaceMethodBean" class="com.kaka.spring.pojo.ReplaceMethodBean"/>

    <bean id="dog" class="com.kaka.spring.pojo.Dog">
        <replaced-method name="say" replacer="replaceMethodBean"/>
    </bean>
  1. 解析property子元素

4.1 源码分析

	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);
			}
		}
	}
	
	public void parsePropertyElement(Element ele, BeanDefinition bd) {
		// 获取property节点的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;
			}
			// 解析property节点的value值(property元素可能还包含子元素)
			Object val = parsePropertyValue(ele, bd, propertyName);
			// 创建PropertyValue 实例承载property节点对应的信息
			PropertyValue pv = new PropertyValue(propertyName, val);
			parseMetaElements(ele, pv);
			pv.setSource(extractSource(ele));
			// 把PropertyValue 实例保存至AbstractBeanDefinition的propertyValues
			bd.getPropertyValues().addPropertyValue(pv);
		}
		finally {
			this.parseState.pop();
		}
	}
  1. 解析qualifier子元素

5.1 源码分析

	public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) {
		NodeList nl = beanEle.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) {
				parseQualifierElement((Element) node, bd);
			}
		}
	}

	public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
		String typeName = ele.getAttribute(TYPE_ATTRIBUTE);
		if (!StringUtils.hasLength(typeName)) {
			error("Tag 'qualifier' must have a 'type' attribute", ele);
			return;
		}
		this.parseState.push(new QualifierEntry(typeName));
		try {
			// 创建qualifier 实例
			AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);
			qualifier.setSource(extractSource(ele));
			// 获取qualifier的value值
			String value = ele.getAttribute(VALUE_ATTRIBUTE);
			if (StringUtils.hasLength(value)) {
				qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value);
			}
			NodeList nl = ele.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				// 处理qualifier的子元素:attribute节点
				if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) {
					Element attributeEle = (Element) node;
					String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE);
					String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE);
					if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) {
						// 创建attribute 实例来承载attribute节点的信息
						BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
						attribute.setSource(extractSource(attributeEle));
						// 把attribute保存至AttributeAccessorSupport的attribute中
						qualifier.addMetadataAttribute(attribute);
					}
					else {
						error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
						return;
					}
				}
			}
			// 保存qualifier对象
			bd.addQualifier(qualifier);
		}
		finally {
			this.parseState.pop();
		}
	}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值