zoukankan      html  css  js  c++  java
  • 转:Spring技术内幕——深入解析Spring架构与设计原理(三)IOC实现原理


    在具体生成BeanDefinition以后。我们举一个对property进行解析的例子来完成对整个BeanDefinition载入过程的 分析,还是在类BeanDefinitionParserDelegate的代码中,它对BeanDefinition中的定义一层一层地进行解析,比如 从属性元素集合到具体的每一个属性元素,然后才是对具体的属性值的处理。根据解析结果,对这些属性值的处理会封装成PropertyValue对象并设置 到BeanDefinition对象中去,如以下代码清单所示。
    Java代码
    1. /** 
    2.  * 这里对指定bean元素的property子元素集合进行解析。 
    3.  */  
    4. public void parsePropertyElements(Element beanEle, BeanDefinition bd) {  
    5.     //遍历所有bean元素下定义的property元素  
    6.     NodeList nl = beanEle.getChildNodes();  
    7.     for (int i = 0; i < nl.getLength(); i++) {  
    8.         Node node = nl.item(i);  
    9.         if (node instanceof Element && DomUtils.nodeNameEquals(node, PROPERTY_ELEMENT)) {  
    10.             //在判断是property元素后对该property元素进行解析的过程  
    11.             parsePropertyElement((Element) node, bd);  
    12.         }  
    13.     }  
    14. }  
    15. public void parsePropertyElement(Element ele, BeanDefinition bd) {  
    16.     //这里取得property的名字  
    17.     String propertyName = ele.getAttribute(NAME_ATTRIBUTE);  
    18.     if (!StringUtils.hasLength(propertyName)) {  
    19.         error("Tag 'property' must have a 'name' attribute", ele);  
    20.         return;  
    21.     }  
    22.     this.parseState.push(new PropertyEntry(propertyName));  
    23.     try {  
    24.         //如果同一个bean中已经有同名的存在,则不进行解析,直接返回。也就是说,如果在同一个bean中有同名的property设置,那么起作用的只是第一个。  
    25.         if (bd.getPropertyValues().contains(propertyName)) {  
    26.             error("Multiple 'property' definitions for property '" + propertyName + "'", ele);  
    27.             return;  
    28.         }  
    29.         //这里是解析property值的地方,返回的对象对应对Bean定义的property属性设置的解析结果,这个解析结果会封装到PropertyValue对象中,然后设置到BeanDefinitionHolder中去。  
    30.         Object val = parsePropertyValue(ele, bd, propertyName);  
    31.         PropertyValue pv = new PropertyValue(propertyName, val);  
    32.         parseMetaElements(ele, pv);  
    33.         pv.setSource(extractSource(ele));  
    34.         bd.getPropertyValues().addPropertyValue(pv);  
    35.     }  
    36.     finally {  
    37.         this.parseState.pop();  
    38.     }  
    39. }  
    40. /** 
    41.  * 这里取得property元素的值,也许是一个list或其他。 
    42.  */  
    43. public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {  
    44.     String elementName = (propertyName != null) ?  
    45.                     "<property> element for property '" + propertyName + "'" :  
    46.                     "<constructor-arg> element";  
    47.   
    48.     // Should only have one child element: ref, value, list, etc.  
    49.     NodeList nl = ele.getChildNodes();  
    50.     Element subElement = null;  
    51.     for (int i = 0; i < nl.getLength(); i++) {  
    52.         Node node = nl.item(i);  
    53.         if (node instanceof Element && !DomUtils.nodeNameEquals(node, DESCRIPTION_ELEMENT) &&  
    54.                 !DomUtils.nodeNameEquals(node, META_ELEMENT)) {  
    55.             // Child element is what we're looking for.  
    56.             if (subElement != null) {  
    57.                 error(elementName + " must not contain more than one sub-element", ele);  
    58.             }  
    59.             else {  
    60.                 subElement = (Element) node;  
    61.             }  
    62.         }  
    63.     }  
    64.     //这里判断property的属性,是ref还是value,不允许同时是ref和value。  
    65.     boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);  
    66.     boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);  
    67.     if ((hasRefAttribute && hasValueAttribute) ||  
    68.             ((hasRefAttribute || hasValueAttribute) && subElement != null)) {  
    69.         error(elementName +  
    70.                 " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);  
    71.     }  
    72.     //如果是ref,创建一个ref的数据对象RuntimeBeanReference,这个对象封装了ref的信息。  
    73.     if (hasRefAttribute) {  
    74.         String refName = ele.getAttribute(REF_ATTRIBUTE);  
    75.         if (!StringUtils.hasText(refName)) {  
    76.             error(elementName + " contains empty 'ref' attribute", ele);  
    77.         }  
    78.         RuntimeBeanReference ref = new RuntimeBeanReference(refName);  
    79.         ref.setSource(extractSource(ele));  
    80.         return ref;  
    81.     } //如果是value,创建一个value的数据对象TypedStringValue ,这个对象封装了value的信息。  
    82.     else if (hasValueAttribute) {  
    83.         TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));  
    84.         valueHolder.setSource(extractSource(ele));  
    85.         return valueHolder;  
    86.     } //如果还有子元素,触发对子元素的解析  
    87.     else if (subElement != null) {  
    88.         return parsePropertySubElement(subElement, bd);  
    89.     }  
    90.     else {  
    91.         // Neither child element nor "ref" or "value" attribute found.  
    92.         error(elementName + " must specify a ref or value", ele);  
    93.         return null;  
    94.     }  
    95. }  
    /** * 这里对指定bean元素的property子元素集合进行解析。 */ public void parsePropertyElements(Element beanEle, BeanDefinition bd) { //遍历所有bean元素下定义的property元素 NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element && DomUtils.nodeNameEquals(node, PROPERTY_ELEMENT)) { //在判断是property元素后对该property元素进行解析的过程 parsePropertyElement((Element) node, bd); } } } public void parsePropertyElement(Element ele, BeanDefinition bd) { //这里取得property的名字 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 { //如果同一个bean中已经有同名的存在,则不进行解析,直接返回。也就是说,如果在同一个bean中有同名的property设置,那么起作用的只是第一个。 if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } //这里是解析property值的地方,返回的对象对应对Bean定义的property属性设置的解析结果,这个解析结果会封装到PropertyValue对象中,然后设置到BeanDefinitionHolder中去。 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(); } } /** * 这里取得property元素的值,也许是一个list或其他。 */ 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. NodeList nl = ele.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element && !DomUtils.nodeNameEquals(node, DESCRIPTION_ELEMENT) && !DomUtils.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; } } } //这里判断property的属性,是ref还是value,不允许同时是ref和value。 boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); 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,创建一个ref的数据对象RuntimeBeanReference,这个对象封装了ref的信息。 if (hasRefAttribute) { String refName = ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(ele)); return ref; } //如果是value,创建一个value的数据对象TypedStringValue ,这个对象封装了value的信息。 else if (hasValueAttribute) { 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. error(elementName + " must specify a ref or value", ele); return null; } }
    比如,再往下看,我们看到像List这样的属性配置是怎样被解析的,依然在BeanDefinitionParserDelegate中:返回的 是一个List对象,这个List是Spring定义的ManagedList,作为封装List这类配置定义的数据封装,如以下代码清单所示。
    Java代码
    1. public List parseListElement(Element collectionEle, BeanDefinition bd) {  
    2.     String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);  
    3.     NodeList nl = collectionEle.getChildNodes();  
    4.     ManagedList<Object> target = new ManagedList<Object>(nl.getLength());  
    5.     target.setSource(extractSource(collectionEle));  
    6.     target.setElementTypeName(defaultElementType);  
    7.     target.setMergeEnabled(parseMergeAttribute(collectionEle));  
    8.     //具体的List元素的解析过程。  
    9.     parseCollectionElements(nl, target, bd, defaultElementType);  
    10.     return target;  
    11. }  
    12. protected void parseCollectionElements(  
    13.         NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {  
    14.     //遍历所有的元素节点,并判断其类型是否为Element。  
    15.     for (int i = 0; i < elementNodes.getLength(); i++) {  
    16.         Node node = elementNodes.item(i);  
    17.         if (node instanceof Element && !DomUtils.nodeNameEquals(node, DESCRIPTION_ELEMENT)) {  
    18.     //加入到target中去,target是一个ManagedList,同时触发对下一层子元素的解析过程,这是一个递归的调用。  
    19.             target.add(parsePropertySubElement((Element) node, bd, defaultElementType));  
    20.         }  
    21.     }  
    22. }  
    public List parseListElement(Element collectionEle, BeanDefinition bd) { String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE); NodeList nl = collectionEle.getChildNodes(); ManagedList<Object> target = new ManagedList<Object>(nl.getLength()); target.setSource(extractSource(collectionEle)); target.setElementTypeName(defaultElementType); target.setMergeEnabled(parseMergeAttribute(collectionEle)); //具体的List元素的解析过程。 parseCollectionElements(nl, target, bd, defaultElementType); return target; } protected void parseCollectionElements( NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) { //遍历所有的元素节点,并判断其类型是否为Element。 for (int i = 0; i < elementNodes.getLength(); i++) { Node node = elementNodes.item(i); if (node instanceof Element && !DomUtils.nodeNameEquals(node, DESCRIPTION_ELEMENT)) { //加入到target中去,target是一个ManagedList,同时触发对下一层子元素的解析过程,这是一个递归的调用。 target.add(parsePropertySubElement((Element) node, bd, defaultElementType)); } } }
    经过这样一层一层的解析,我们在XML文件中定义的BeanDefinition就被整个给载入到了IoC容器中,并在容器中建立了数据映射。在 IoC容器中建立了对应的数据结构,或者说可以看成是POJO对象在IoC容器中的映像,这些数据结构可以以 AbstractBeanDefinition为入口,让IoC容器执行索引、查询和操作。

    在我的感觉中,对核心数据结构的定义和处理应该可以看成是一个软件的核心部分了。所以,这里的BeanDefinition的载入可以说是IoC容器的核心,如果说IoC容器是Spring的核心,那么这些BeanDefinition就是Spring的核心的核心了!

    呵呵,这部分代码数量不小,但如果掌握这条主线,其他都可以举一反三吧,就像我们掌握了操作系统启动的过程,以及在操作系统设计中的核心数据结构 像进程数据结构,文件系统数据结构,网络协议数据结构的设计和处理一样,对整个系统的设计原理,包括移植,驱动开发和应用开发,是非常有帮助的!
  • 相关阅读:
    手机品牌大集合
    什么是全角和半角?
    String,StringBuffer,StringBuild的区别
    什么是法人?法定代表人?法人代表?法定代表?
    如何得到table里面的ID
    Jquery代码编写工具Komodo
    jquery 验证email
    jQuery使用手册 (转)
    centos iptables 防火墙 命令
    php webservice实例(转载)
  • 原文地址:https://www.cnblogs.com/xinzhuangzi/p/4100518.html
Copyright © 2011-2022 走看看