当前位置:首页 >> 能源/化工 >>

2.3.2 BeanDefinition的载入和解析(4)


上面是具体生成 BeanDefinition 的地方。在这里,我们举一个对 property 进行解析的例 子来完成对整个 BeanDefinition 载入过程的分析,还是在类 BeanDefinitionParserDelegate 的 代码中,它对 BeanDefinition 中的定义一层一层地进行解析,比如从属性元素集合到具体的 每一个属性元素,然后才是对具体的属性值的

处理。根据解析结果,对这些属性值的处理会 封装成 PropertyValue 对象并设置到 BeanDefinition 对象中去,如代码清单 2-18 所示。 代码清单 2-18 对 BeanDefinition 中 Property 元素集合的处理
1. //这里对指定 bean 元素的 property 子元素集合进行解析。 2. public void parsePropertyElements(Element beanEle, 3. BeanDefinition bd) { 4. 5. 6. 7. 8. //遍历所有 bean 元素下定义的 property 元素。 NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element &&

9. DomUtils.nodeNameEquals(node, PROPERTY_ 10. ELEMENT)) { 11. 12. //在判断是 property 元素后对该 property 元素进行解析的过程。 13. 14. bd); 15. 16. 17. } 18. public void parsePropertyElement(Element ele, BeanDefinition 19. bd) { 20. 21. //这里取得 property 的名字。 String propertyName = } } parsePropertyElement((Element) node,

22. ele.getAttribute(NAME_ATTRIBUTE); 23. 24. if (!StringUtils.hasLength(propertyName)) { error("Tag 'property' must have a 'name'

25. attribute", ele); 26. 27. 28. } this.parseState.push(new return;

29. PropertyEntry(propertyName)); 30. 31. try { /**

32. 33. *如果同一个 bean 中已经有同名 property 的存在,则不进行解析,直 34. 接返回。也就是说, 35. 36. *如果在同一个 bean 中有同名的 property 设置,那么起作用的只是第 37. 一个。 38. 39. */ if

40. (bd.getPropertyValues().contains(propertyName)) { 41. error("Multiple 'property'

42. definitions for property '" + 43. propertyName + "'", ele); 44. 45. 46. 47. 48. *这里是解析 property 值的地方,返回的对象对应对 Bean 定义的 prope 49. rty 属性 50. 51. *设置的解析结果,这个解析结果会封装到 PropertyValue 对象中,然 52. 后设置到 53. 54. 55. *BeanDefinitionHolder 中去。 */ Object val = parsePropertyValue(ele, bd, } /** return;

56. propertyName); 57. PropertyValue pv = new

58. PropertyValue(propertyName, val); 59. 60. 61. 62. 63. 64. 65. 66. } 67. //这里取得 property 元素的值,也许是一个 list 或其他。 68. public Object parsePropertyValue(Element ele, BeanDefinition 69. bd, String propertyName) { } } finally { this.parseState.pop(); parseMetaElements(ele, pv); pv.setSource(extractSource(ele)); bd.getPropertyValues().addPropertyValue(pv);

70. 71.

String elementName = (propertyName != null) ? "<property> element

72. for property '" + propertyName + "'" : 73. 74. element"; 75. // Should only have one child element: ref, value, "<constructor-arg>

76. list, etc. 77. 78. 79. 80. 81. NodeList nl = ele.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element &&

82. !DomUtils.nodeNameEquals(node, DESCRIPTION_ 83. 84. 85. !DomUtils.nodeNameEquals(node, META_ELEMENT)) { 86. 87. looking for. 88. 89. if (subElement != null) { error(elementName + " must // Child element is what we're ELEMENT) &&

90. not contain more than one sub-element", 91. 92. 93. 94. 95. 96. 97. 98. } //这里判断 property 的属性,是 ref 还是 value,不允许同时 } } ele); } else { subElement = (Element) node;

99. 是 ref 和 value。 100. boolean hasRefAttribute =

101. ele.hasAttribute(REF_ATTRIBUTE); 102. boolean hasValueAttribute =

103. ele.hasAttribute(VALUE_ATTRIBUTE); 104. 105. if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute ||

106. hasValueAttribute) && subElement != null)) { 107. error(elementName +

108.

" is only allowed to contain

109. either 'ref' attribute OR 'value' 110. 111. 112. } //如果是 ref,创建一个 ref 的数据对象 RuntimeBeanReferen attribute OR sub-element", ele);

113. ce,这个对象封装了 ref 的信息。 114. 115. if (hasRefAttribute) { String refName =

116. ele.getAttribute(REF_ATTRIBUTE); 117. 118. if (!StringUtils.hasText(refName)) { error(elementName + " contains empty

119. 'ref' attribute", ele); 120. 121. } RuntimeBeanReference ref = new

122. RuntimeBeanReference(refName); 123. 124. 125. } ref.setSource(extractSource(ele)); return ref;

126. //如果是 value,创建一个它的数据对象 TypedStringValue,这个对 127. 象封装了 value 的信息。 128. 129. else if (hasValueAttribute) { TypedStringValue valueHolder = new

130. TypedStringValue(ele.getAttribute 131. (VALUE_ATTRIBUTE)); 132. 133. 134. 135. 136. 137. bd); 138. 139. 140. } else { // Neither child element nor "ref" or valueHolder.setSource(extractSource(ele)); return valueHolder; } //如果还有子元素,触发对子元素的解析。 else if (subElement != null) { return parsePropertySubElement(subElement,

141. "value" attribute found. 142. error(elementName + " must specify a ref or

143. value", ele); 144. 145. } return null;

146. }

这里是对 property 子元素的解析过程,Array、List、Set、Map、Prop 等各种元素都会在 这里进行解析,生成对应的数据对象,比如 ManagedList、ManagedArray、ManagedSet 等。 这些 Managed 类是 Spring 对具体的 BeanDefinition 的数据封装。具体的解析过程读者可以 去看看自己感兴趣的部分,比如 parseArrayElement、parseListElement、parseSetElement、 parseMapElement、parsePropElement 对应着不同类型的数据解析,同时这些具体的解析方法 在 BeanDefinitionParserDelegate 类中也都能够找到。因为方法命名很清晰,所以从方法名字 上就能够很快地找到。下面,以对 Property 的元素进行解析的过程为例,通过它的实现来说 明这个具体的解析过程是怎样完成的,如代码清单 2-19 所示。 代码清单 2-19 对属性元素进行解析
1. public Object parsePropertySubElement(Element ele, 2. BeanDefinition bd, String 3. defaultValueType) { 4. 5. 6. 7. 8. { 9. BeanDefinitionHolder nestedBd = } else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) if (!isDefaultNamespace(ele.getNamespaceURI())) { return parseNestedCustomElement(ele, bd);

10. parseBeanDefinitionElement(ele, bd); 11. 12. if (nestedBd != null) { nestedBd =

13. decorateBeanDefinitionIfRequired(ele, nestedBd, bd); 14. 15. 16. 17. 18. { 19. 20. bean. 21. String refName = // A generic reference to any name of any } else if (DomUtils.nodeNameEquals(ele, REF_ELEMENT)) } return nestedBd;

22. ele.getAttribute(BEAN_REF_ATTRIBUTE); 23. 24. 25. boolean toParent = false; if (!StringUtils.hasLength(refName)) { // A reference to the id of another

26. bean in the same XML file.

27.

refName =

28. ele.getAttribute(LOCAL_REF_ATTRIBUTE); 29. 30. { 31. // A reference to the id of if (!StringUtils.hasLength(refName))

32. another bean in a parent context. 33. refName =

34. ele.getAttribute(PARENT_REF_ATTRIBUTE); 35. 36. toParent = true; if

37. (!StringUtils.hasLength(refName)) { 38. error("'bean',

39. 'local' or 'parent' is required for <ref> 40. 41. 42. 43. 44. 45. 46. } if (!StringUtils.hasText(refName)) { error("<ref> element contains empty } } element", ele); return null;

47. target attribute", ele); 48. 49. 50. } RuntimeBeanReference ref = new return null;

51. RuntimeBeanReference(refName, toParent); 52. 53. 54. 55. } else if (DomUtils.nodeNameEquals(ele, ref.setSource(extractSource(ele)); return ref;

56. IDREF_ELEMENT)) { 57. 58. 59. } else if (DomUtils.nodeNameEquals(ele, return parseIdRefElement(ele);

60. VALUE_ELEMENT)) { 61. return parseValueElement(ele,

62. defaultValueType); 63. 64. } else if (DomUtils.nodeNameEquals(ele, NULL_ELEMENT))

65. { 66. // It's a distinguished null value. Let's

67. wrap it in a TypedStringValue 68. // object in order to preserve the source

69. location. 70. TypedStringValue nullHolder = new

71. TypedStringValue(null); 72. 73. 74. 75. } else if (DomUtils.nodeNameEquals(ele, nullHolder.setSource(extractSource(ele)); return nullHolder;

76. ARRAY_ELEMENT)) { 77. 78. 79. 80. { 81. 82. 83. 84. { 85. 86. 87. 88. { 89. 90. 91. } else if (DomUtils.nodeNameEquals(ele, return parseMapElement(ele, bd); } else if (DomUtils.nodeNameEquals(ele, MAP_ELEMENT)) return parseSetElement(ele, bd); } else if (DomUtils.nodeNameEquals(ele, SET_ELEMENT)) return parseListElement(ele, bd); } else if (DomUtils.nodeNameEquals(ele, LIST_ELEMENT)) return parseArrayElement(ele, bd);

92. PROPS_ELEMENT)) { 93. 94. 95. 96. } else { error("Unknown property sub-element: [" + return parsePropsElement(ele);

97. ele.getNodeName() + "]", ele); 98. 99. 100. } } return null;

我们看看类似 List 这样的属性配置是怎样被解析的,依然在 BeanDefinitionParser-Delegate 中,返回的是一个 List 对象,这个 List 是 Spring 定义的 ManagedList,作为封装 List 这类配置定义的数据封装,如代码清单 2-20 所示。 代码清单 2-20 解析 BeanDefinition 中的 List 元素
1. public List parseListElement(Element collectionEle, 2. BeanDefinition bd) { 3. String defaultElementType =

4. collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE); 5. 6. NodeList nl = collectionEle.getChildNodes(); ManagedList<Object> target = new

7. ManagedList<Object>(nl.getLength()); 8. 9. 10. target.setSource(extractSource(collectionEle)); target.setElementTypeName(defaultElementType); target.setMergeEnabled(parseMergeAttribute(collectio

11. nEle)); 12. 13. //具体的 List 元素的解析过程。 parseCollectionElements(nl, target, bd,

14. defaultElementType); 15. 16. } 17. protected void parseCollectionElements( 18. NodeList elementNodes, Collection<Object> return target;

19. target, BeanDefinition bd, 20. String defaultElementType) { 21. 22. 23. 24. //遍历所有的元素节点,并判断其类型是否为 Element。 for (int i = 0; i < elementNodes.getLength(); i++) { Node node = elementNodes.item(i); if (node instanceof Element &&

25. !DomUtils.nodeNameEquals(node, DESCRIPTION_ 26. ELEMENT)) { 27. 28. /** *加入到 target 中,target 是一个 ManagedList,同时触发对

29. 下一层子元素的解析过程, 30. 31. 32. 33. target.add(parsePropertySubElement((Element) node, bd, *这是一个递归调用。 */

34. defaultElement 35. 36. 37. 38. } } Type)); }

经过这样逐层地解析,我们在 XML 文件中定义的 BeanDefinition 就被整个给载入到了 IoC 容器中,并在容器中建立了数据映射。在 IoC 容器中建立了对应的数据结构,或者说可 以看成是 POJO 对象在 IoC 容器中的映像, 这些数据结构可以以 AbstractBeanDefinition 为入 口,让 IoC 容器执行索引、查询和操作。简单的 POJO 操作背后其实并不简单,经过以上的 载入过程,IoC 容器大致完成了管理 Bean 对象的数据准备工作(或者说是初始化过程)。 但是,重要的依赖注入实际上在这个时候还没有发生,现在,在 IoC 容器 BeanDefinition 中 存在的还只是一些静态的配置信息。严格地来说,这时候的容器还没有完全起作用,要完全 发挥容器的作用,还需完成数据向容器的注册。


相关文章:
2.3.2 BeanDefinition的载入和解析(4)
2.3.2 BeanDefinition的载入和解析(4) 隐藏>> 上面是具体生成 BeanDefinition 的地方。在这里,我们举一个对 property 进行解析的例 子来完成对整个 BeanDefinitio...
2.3.2 BeanDefinition的载入和解析(3)
2.3.2 BeanDefinition的载入和解析(3)_电子/电路_工程科技_专业资料。具体的...parseBeanDefinitionElement(Element ele, BeanDefinition 3. containingBean) { 4...
2.3.2 BeanDefinition的载入和解析(1)
2.3.2 BeanDefinition 的载入和解析 对 IoC 容器来说, BeanDefinition 的载入...protected final void refreshBeanFactory() throws BeansException { 2. 3. 4...
2.3.2 BeanDefinition的载入和解析(2)
2.3.2 BeanDefinition的载入和解析(2)_其它语言学习_外语学习_教育专区。接着...BeansException, IOException { 4. 5. 6. 7. 8. 9. 10. 11. 12. 13....
2.3.3 BeanDefinition在IoC容器中的注册
= new ConcurrentHashMap 4. <STRING,&NBSP;BEANDEFINITION>(); 将解析得到的 BeanDefinition 向 IoC 容器中的 beanDefinitionMap 注册的过程是在载入 Bean...
2.4 IoC容器的依赖注入(3)
1/4 同系列文档 2.1.1 IoC容器和依赖反转模... 2.2.3 ApplicationContext...自对 *BeanDefinition 的解析。 */ 5. //具体的解析过程可以参看载入和解析 ...
2.3.1 BeanDefinition的Resource定位(2)
protected Resource getResourceByPath(String path) { 2. 3. 4. 5. 6. }...这些数据的读入将在下面看到的 BeanDefinition 的载入和解析中来完成。仍然以水桶...
Java笔试题(一)答案
(2)接口里只 能定义静态常量属性(3)接口里不能包含初始化块和构造方法(4)一...答: BeanFactory负责读取bean配置文档, 管理bean的加载, 实例化, 维护bean 之间...
2.3.1 BeanDefinition的Resource定位(1)
2. 3. 4. 5. 6. 7. 8. 9. 10. 11. } //这个构造函数的 ...这个 refresh *启动了 BeanDefinition 的载入过程,我们会在下面进行详 细分析。...
Spring源码解析一
读取配置信息的 BeanDefinitionReader,这里是 XmlBeanDefinitionReader 配置给 BeanFactory 4. 从定义好的资源位置读入配置信息,具体的解析过程由 XmlBeanDefinition...
更多相关标签:
beandefinition | beandefinition 详解 | beandefinitionparser | root beandefinition | beandefinition是什么 | beandefinition 使用 | dom4j解析xml生成bean | gson解析bean |