概述
- Constructor-arg子元素解析
- property子元素解析
constructor-arg子元素解析
简单例子
| 1 | public class StudentService { | 
| 1 | <bean id="bookService" class="org.springframework.core.service.BookService"/> | 
StudentService 定义一个构造函数,配置文件中使用 constructor-arg 元素对其配置,该元素可以实现对 StudentService 自动寻找对应的构造函数,并在初始化的时候将值当做参数进行设置。parseConstructorArgElements() 方法完成 constructor-arg 子元素的解析。
| 1 | public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) { | 
遍历所有子元素,如果为 constructor-arg 则调用 parseConstructorArgElement() 进行解析。
| 1 | public void parseConstructorArgElement(Element ele, BeanDefinition bd) { | 
首先获取 index、type、name 三个属性值,然后根据是否存在 index 来区分。其实两者逻辑都差不多,总共分为如下几个步骤(以有 index 为例):
- 构造 ConstructorArgumentEntry 对象并将其加入到 ParseState 队列中。ConstructorArgumentEntry 表示构造函数的参数。
- 调用 parsePropertyValue()解析 constructor-arg 子元素,返回结果值
- 根据解析的结果值构造 ConstructorArgumentValues.ValueHolder实例对象
- 将 type、name 封装到 ConstructorArgumentValues.ValueHolder中,然后将 ValueHolder 实例对象添加到 indexedArgumentValues 中。
无 index 的处理逻辑差不多,只有几点不同:构造 ConstructorArgumentEntry 对象时是调用无参构造函数;最后是将 ValueHolder 实例添加到 genericArgumentValues 中。
parsePropertyValue() 对子元素进一步解析。
| 1 | public Object parsePropertyValue(Element ele, BeanDefinition bd, | 
- 首先略过description或者meta 
- 提取 constructor-arg 子元素的 ref 和 value 的属性值,对其进行判断,以下两种情况是不允许存在的 - ref 和 value 属性同时存在
- 存在 ref 或者 value 且又有子元素
 
- 若存在 ref 属性,则获取其值并将其封装进 RuntimeBeanReference 实例对象中 - 1 - <construct-arg ref=""/> 
- 若存在 value 属性,则获取其值并将其封装进 TypedStringValue 实例对象中 - 1 - <construct-arg value="a"/> 
- 如果子元素不为空,则调用 - parsePropertySubElement()进行子元素进一步处理- 1 
 2
 3
 4
 5- <construct-arg> 
 <map>
 <entry key="" value=""></entry>
 </map>
 </construct-arg>- 具体源码如下 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84- 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 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子元素的解析
 else if (nodeNameEquals(ele, NULL_ELEMENT)) {
 // It's a distinguished null value. Let's wrap it in a TypedStringValue
 // object in order to preserve the source location.
 TypedStringValue nullHolder = new TypedStringValue(null);
 nullHolder.setSource(extractSource(ele));
 return nullHolder;
 }
 // 解析数组
 else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
 return parseArrayElement(ele, bd);
 }
 // 解析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;
 }
 }
上面我们已经大体上了解construct的解析过程,对各个子类进行分类处理,详细情况如果各位有兴趣可以移步源码进行深一步的探究。
property 子元素解析
我们一般使用如下方式来使用 property 子元素。
| 1 | <bean id="studentService" class="org.springframework.core.service.StudentService"> | 
   对于 property 子元素的解析,Spring 调用 parsePropertyElements()。如下:
| 1 | public void parsePropertyElements(Element beanEle, BeanDefinition bd) { | 
 constructor-arg 子元素差不多,同样是提取所有的 property 的子元素,然后调用 parsePropertyElement() 进行分析。
| 1 | public void parsePropertyElement(Element ele, BeanDefinition bd) { | 
与解析 constructor-arg 子元素步骤差不多。调用 parsePropertyValue() 解析子元素属性值,然后根据该值构造 PropertyValue 实例对象并将其添加到 BeanDefinition 中的 MutablePropertyValues 中。
qualifier子元素解析
对于qualifier元素的获取,我们接触更多的是注解的形式,在使用spring框架中进行自动注入时,spring容器中匹配的候选Bean数目必须有且仅有一个。当找不到一个匹配的bean时,Spring容器将抛出BeanCreationException异常,并且指出必须至少拥有一个匹配的bean。
spring允许我们通过qualifier指定注入bean的名称,这样歧义就消除了,而对于配置方式如下
| 1 | <bean id="" name=""> | 
解析过程与之前大同小异,这里不再重复叙述