spring bean子标签 loopup-method、replaced-method基本用法参见:http://blog.csdn.net/disiwei1012/article/details/70495940
本节介绍bean标签的其他子标签的解析
1.子元素meta解析
<bean id="test" class="com.demo.test">
<meta key="testStr" value="aaa"/>
</bean>
//解析子元素meta
parseMetaElements(ele, bd);
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
NodeList nl = ele.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
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);
//构造BeanMetadataAttribute
BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
attribute.setSource(extractSource(metaElement));
attributeAccessor.addMetadataAttribute(attribute);
}
}
}
2.子元素loopup-method解析
<bean id="test" class="com.demo.test">
<lookup-method name="getBean" bean="teacher"/>
</bean>
<bean id="teacher" class="com.test.teacher"/>
//解析子元素loopup-method
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
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
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);
}
}
}
3.子元素replaced-method解析
<bean id="test" class="com.demo.test">
<replaced-method name="changeMe" replacer="replacer"/>
</bean>
<bean id="replacer" class="com.test.replacer"/>
//解析子元素replaced-method
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
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;
//name属性
String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
//replacer属性
String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
//获取arg-type标签,参数类型
// 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);
}
}
}
4.子元素constructor-arg解析
4.1 举例说明
举个例子的话,会更直观一点:
public class Man {
private String name ;
private int age;
private List hobby;
private Map friends;
private Set set;
private boolean ifMarried;
public Man() {
}
public Man(String name, int age,List hobby,Map friends,Set set,boolean ifMarried){
this.name = name;
this.age = age;
this.hobby = hobby;
this.friends = friends;
this.set = set;
this.ifMarried = ifMarried;
}
public String getInfo(){
String info = "姓名:"+this.name+"\n年龄:"+this.age+"\n爱好:"+this.hobby+"\n朋友:"+this.friends+"\n婚否:"+this.ifMarried+"\n其他的:"+this.set;
return info;
}
}
<bean id="man" class="com.spring.test.Man">
<constructor-arg value="zzy" index="0"></constructor-arg>
<constructor-arg value="10" index="1"></constructor-arg>
<constructor-arg>
<list>
<value>movie</value>
<value>music</value>
</list>
</constructor-arg>
<constructor-arg>
<set>
<value>Lady is GaGa</value>
<value>GaGa is Lady</value>
</set>
</constructor-arg>
<constructor-arg>
<map>
<entry key="liuhua" value="man"></entry>
<entry key="xujinglei" value="female"></entry>
</map>
</constructor-arg>
<constructor-arg index="5" value="0"></constructor-arg>
</bean>
4.2 具体代码解析
对于construction-arg 子元素的解析,spring 是通过 BeanDefinitionParserDelegate. parseConstructorArgElements(Element beanEle, BeanDefinition bd); 方法来实现的:
/**
* Parse constructor-arg sub-elements of the given bean element.
*/
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
//解析constructor-arg
parseConstructorArgElement((Element) node, bd);
}
}
}
追踪下去如下:
/**
* 解析constructor-arg元素
*/
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);
//如果constructor-arg标签index属性有值
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));
//解析constructor-arg标签其他属性值,和子标签
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);
}
}//如果constructor-arg标签index属性没有值
else {
try {
this.parseState.push(new ConstructorArgumentEntry());
//解析constructor-arg标签其他属性值,和子标签
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. 解析constructor-arg标签
2. ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素
3. 将type、name、index属性一起封装到ConstructorArgumentValues.ValueHolder中。并将ValueHolder中添加至当前BeanDefinition的ConstructorArgumentValues的IndexedArgumentValue中
如果没有指定index属性
1. 解析constructor-arg标签
2. ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素
3. 将type、name、index属性一起封装到ConstructorArgumentValues.ValueHolder中。并将ValueHolder中添加至当前BeanDefinition的ConstructorArgumentValues的GenericArgumentValue中
如果指定了index属性是保存到IndexedArgumentValue中,否则保存到GenericArgumentValue。
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
String elementName = (propertyName != null) ?
"<property> element for property '" + propertyName + "'" :
"<constructor-arg> element";
//一个constructor-arg标签只能有一个子标签:ref,value,list等
NodeList nl = ele.getChildNodes();
Element subElement = null;
//判断是否只有一个子标签(忽略description和meta标签)
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
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;
}
}
}
//constructor-arg标签的ref属性
boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
//constructor-arg标签的value属性
boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
/**
* 1.constructor-arg标签不能同时具有ref和value属性
* 1.constructor-arg如果具有ref和value属性之一,则不能再有子元素(忽略description和meta标签)
*/
if ((hasRefAttribute && hasValueAttribute) ||
((hasRefAttribute || hasValueAttribute) && subElement != null)) {
error(elementName +
" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
}
//解析constructor-arg标签的ref属性
if (hasRefAttribute) {
//获取ref属性值
String refName = ele.getAttribute(REF_ATTRIBUTE);
if (!StringUtils.hasText(refName)) {
error(elementName + " contains empty 'ref' attribute", ele);
}
//使用RuntimeBeanReference封装ref属性
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
ref.setSource(extractSource(ele));
return ref;
}
//解析constructor-arg标签的value属性
else if (hasValueAttribute) {
//使用TypedStringValue封装value属性
TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
valueHolder.setSource(extractSource(ele));
return valueHolder;
}
//解析constructor-arg标签的子元素
else if (subElement != null) {
return parsePropertySubElement(subElement, bd);
}
else {
//如果即没有子元素、也没有ref、value属性,则返回null
error(elementName + " must specify a ref or value", ele);
return null;
}
}
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
if (!isDefaultNamespace(ele)) {
return parseNestedCustomElement(ele, bd);
}
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.子元素propertyg解析
5.1 基本用法
public class Animal {
public String type;
public Set<Integer> age;
private Map<String, Integer> sell;
public Animal() {
}
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(String type) {
this.type = type;
}
/**
* @return the age
*/
public Set<Integer> getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(Set<Integer> age) {
this.age = age;
}
/**
* @return the sell
*/
public Map<String, Integer> getSell() {
return sell;
}
/**
* @param sell the sell to set
*/
public void setSell(Map<String, Integer> sell) {
this.sell = sell;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Animal [type=" + type + ", age=" + age + ", sell=" + sell + "]";
}
}
<?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-2.5.xsd">
<bean id="animal" class="test.property.Animal">
<property name="type" value="cat"></property>
<property name="age">
<set>
<value>1</value>
<value>2</value>
<value>3</value>
</set>
</property>
<property name="sell">
<map>
<entry key="blue" value="111"></entry>
<entry key="red" value="22"></entry>
</map>
</property>
</bean>
</beans>
5.2 具体代码解析
/**
* Parse property sub-elements of the given bean element.
*/
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
// 这里进去
parsePropertyElement((Element) node, bd);
}
}
}
/**
* Parse a property element.
*/
public void parsePropertyElement(Element ele, BeanDefinition bd) {
// 获取配置文件中name 的值
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
// 不容许多次对同一属性配置
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName
+ "'", ele);
return;
}
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
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.
// 应该只有一个子元素:REF,值,列表等。
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;
}
}
}
// 解析 ref
boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
// 解析 value
boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
if ((hasRefAttribute && hasValueAttribute)
|| ((hasRefAttribute || hasValueAttribute) && subElement != null)) {
/*
* 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) {
String refName = ele.getAttribute(REF_ATTRIBUTE);
if (!StringUtils.hasText(refName)) {
error(elementName + " contains empty 'ref' attribute", ele);
}
// ref 属性的处理 , 使用RuntimeBeanReference封装对应的ref名称
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 也没有子元素的,Spring只好丢出异常
error(elementName + " must specify a ref or value", ele);
return null;
}
}
6.子元素qualifier解析
<bean id="test" class="com.demo.test">
<qualifier type="org.Springframework.beans.factory.annotation.Qualifier" value="ts"/>
</bean>
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);
//必须要有type属性
if (!StringUtils.hasLength(typeName)) {
error("Tag 'qualifier' must have a 'type' attribute", ele);
return;
}
this.parseState.push(new QualifierEntry(typeName));
try {
//使用AutowireCandidateQualifier封装
AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);
qualifier.setSource(extractSource(ele));
//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);
//解析子标签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)) {
BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
attribute.setSource(extractSource(attributeEle));
qualifier.addMetadataAttribute(attribute);
}
else {
error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
return;
}
}
}
bd.addQualifier(qualifier);
}
finally {
this.parseState.pop();
}
}