本身動手編寫IOC框架(二)

  萬事開頭難,上篇已經起了一個頭,以後的事情相對就簡單了。上次定義了框架所需的dtd也就是規定了xml中該怎麼寫,有哪些元素。而且咱們也讓dtd和xml綁定在了一塊兒,使dtd對xml的格式進行校驗,而且在DocumentHolder中提供了根據xml文件路徑獲取xml文件的Document對象。此次咱們應該把重點轉到從document對象中拿到咱們所須要的標籤Element元素了。java

  一步步來,咱們有了document對象,咱們接下來開始從document對象下手,順便說下本框架項目採用分層思想,一層層的進行處理,對於對ioc不感冒的小夥伴們也能夠參考下這種思想。咱們在xml包下創建element.loader包,因爲在這一階段咱們還不知道咱們到底須要xml中的哪些元素因此咱們準備在這一層提供一個通用的loader層,專門將xml文件中的全部標籤統一加載到內存並按照良好的格式保存,而且根據提供獲取全部元素集合的方法方便下一層使用,根據咱們定義的dtd文件咱們知道,xml文件中就兩種元素beans和bean元素,咱們重點就考慮bean元素,並且每一個bean元素必有id元素,咱們還應該提供根據id獲取bean元素的方法。那麼下面咱們到底應該怎麼去依據document參數提供這兩個方法呢,難道每次咱們就從document開始往下遍歷嗎,因此我給出的方法就是再加一個加載全部元素的方法,依據document將全部element對象加載到內存中使用鍵值對的方式將id和Element對象保存起來。定義接口ElementLoader以下node

package com.tear.ioc.bean.xml.element.loader;

import java.util.Collection;

import org.dom4j.Document;
import org.dom4j.Element;

/**
 * 載入一個Document對象的全部Element提供保存
 * @author rongdi
 */
public interface ElementLoader {
    /**
     * 加入一個Document對象的全部Element
     * 
     * @param document
     */
    public void addBeanElements(Document document);

    /**
     * 根據元素的id得到Element對象
     * 
     * @param id
     * @return
     */
    public Element getBeanElement(String id);

    /**
     * 返回所有的Element
     * 
     * @return
     */
    public Collection<Element> getBeanElements();
}

從上面的方法名咱們能夠看出咱們沒有管根元素beans,若是須要處理beans,小夥伴們能夠本身提供相似的方法,這裏咱們忽略了。spring

實現類ElementLoaderImpl以下數組

package com.tear.ioc.bean.xml.element.loader;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;

public class ElementLoaderImpl implements ElementLoader {
    /**
     * 定義一個Map來保存一個Document對象中根節點(beans)下全部Element對象
     * Map的key對應bean元素的id屬性,而Map的value對應bean元素
     */
    Map<String,Element> beanElements = new HashMap<String,Element>();
    /**
     * 將一個Document對象的全部Element加入到保存Element對象的Map中
     * @param document
     */
    @Override
    public void addBeanElements(Document document) {
        /**
         * 先獲得根節點beans再獲得bean節點
         */
        @SuppressWarnings("unchecked")
        List<Element> elementList = document.getRootElement().elements();
        /**
         * 循環將全部的元素的id屬性和元素一一對應的加入到Map中
         */
        for(Element e:elementList) {
            /**
             * 獲得元素的id屬性
             */
            String id = e.attributeValue("id");
            /**
             * 將id屬性和該元素一塊兒添加到Map中
             */
            this.beanElements.put(id, e);
        }
    }

    @Override
    public Element getBeanElement(String id) {
        /**
         * 根據id從保存全部元素的Map中取出對應的元素
         */
        return beanElements.get(id);
    }

    @Override
    public Collection<Element> getBeanElements() {
        /**
         * 獲得保存全部元素的Map中的全部value的集合,也就是全部的元素的集合
         */
        return beanElements.values();
    }

}

到了這一層咱們已經能夠根據document對象獲得全部的標籤Element對象的集合,也能夠根據id獲取單個Element,那麼咱們下一層,就能夠根據Element對象去解析bean元素的屬性或者bean元素的子元素了。新建element.parser包,在parser定義接口BeanElementParser:框架

package com.rongdi.ioc.xml.element.parser;

import java.util.List;
import org.dom4j.Element;

import com.rongdi.ioc.xml.autowire.Autowire;
import com.rongdi.ioc.xml.element.LeafElement;
import com.rongdi.ioc.xml.element.PropertyElement;

/**
 * 這是解析裝載的element的接口,提供一系列的方法
 * @author rongdi
 *
 */
public interface BeanElementParser {
    /**
     * 判斷一個bean元素是否須要延遲加載
     * @param element
     * @return
     */
    public boolean isLazy(Element beanElement);
    
    /**
     * 得到一個bean元素下的constructor-arg(構造方法參數)的子標籤
     * @param element
     * @return
     */
    public List<Element> getConstructorArgsElements(Element bean);
    
    /**
     * 獲得元素屬性爲name的屬性值
     * @param element
     * @param name
     * @return
     */
    public String getAttribute(Element element, String name);
    
    /**
     * 判斷一個bean元素是否配置爲單態
     * @param element
     * @return
     */
    public boolean isSingleton(Element bean);
    
    /**
     * 得到一個bean元素下全部property元素
     * @param element
     * @return
     */
    public List<Element> getPropertyElements(Element bean);
    
    /**
     * 返回一個bean元素對應的Autowire對象
     * @param element
     * @return
     */
    public Autowire getAutowire(Element bean);
    
    /**
     * 獲取bean元素下全部constructor-arg的值(包括value和ref)
     * @param element
     * @return
     */
    public List<LeafElement> getConstructorValue(Element bean);
    
    /**
     * 獲取bean元素下全部property元素的值(包括value和ref)
     * @param element
     * @return
     */
    List<PropertyElement> getPropertyValue(Element bean);
}

從上面能夠看出咱們的處理源從上一層的Document變成了Element對象了,這就是分層思想,一層層處理,一層層傳遞。從上面能夠看出咱們自定義了一些bean元素,其中LeafElement元素是一個接口,咱們定義了全部咱們須要的元素的兩個共同屬性type和value,也就是任何標籤元素不論是value仍是ref最主要的屬性都是這兩個好比以下xml片斷:dom

<bean id="test12" class="com.rongdi.Test17">
        <property name="property1">
            <value type="java.lang.String">rongdi</value>
        </property>
        <property name="property2">
            <ref bean="test13"/>
        </property>
        <property name="property3">
            <value type="java.lang.Integer">22</value>
        </property>
        <property name="property4">
            <collection type="list">
                <value type="java.lang.Integer">1212</value>
                <value type="java.lang.String">rongdi</value>
            </collection>
        </property>
    </bean>

ValueElement和RefElement代碼以下ide

package com.tear.ioc.bean.xml.element;

/**
 * 這是表明ref標籤的節點元素,實現了LeafElement接口
 * @author rongdi
 */
public class RefElement implements LeafElement {
    /**
     * 定義一個成員變量用來保存ref元素的value值,也就是開始標籤和結束標籤之間的值
     */
    private Object value;
    /**
     * 用構造方法將ref元素的value值傳給成員變量保存
     * @param value
     */
    public RefElement(Object value) {
        this.value = value;
    }
    /**
     * 重寫接口中的getType方法,返回本身的類型,因爲該類型是ref的因此能夠直接返回ref
     */
    @Override
    public String getType() {
        return "ref";
    }
    /**
     * 重寫自接口的getValue方法,返回元素的value值該value已經經過構造方法保存到成員變量
     * 中了,因此直接返回該成員變量就能夠了
     */
    @Override
    public Object getValue() {
        
        return this.value;
    }

}
package com.tear.ioc.bean.xml.element;

/**
 * 這是表明value標籤的節點元素,實現了LeafElement接口
 * @author rongdi
 */
public class ValueElement implements LeafElement {
    /**
     * 同RefNodeElement元素同樣也要提供一個成員變量保存元素之間的value值
     */
    private Object value;
    /**
     * 用構造方法將value元素的value值傳給成員變量保存
     * @param value
     */
    public ValueElement(Object value) {
        this.value = value;
    }
    /**
     * 重寫接口中的getType方法,返回本身的類型,因爲該類型是value的因此能夠直接返回value字符串
     */
    @Override
    public String getType() {
        
        return "value";
    }
    /**
     * 重寫自接口的getValue方法,返回元素的value值該value已經經過構造方法保存到成員變量
     * 中了,因此直接返回該成員變量就能夠了
     */
    @Override
    public Object getValue() {
    
        return this.value;
    }

}

至於PropertyElement根據上面標籤能夠看出他自己有一個name屬性,還有一個子元素要麼是value要麼是ref代碼以下測試

package com.tear.ioc.bean.xml.element;


/**
 * 這是ref和value節點元素的上層元素,該元素可能包含ref或者是value子元素
 * @author rongdi
 *
 */
public class PropertyElement {
    /**
     * 用來保存property元素的name屬性值
     */
    private String name;
    /**
     * 用來保存Property元素下的ref或者是value子元素
     */
    private LeafElement leafElement;
    /**
     * 取出property元素的name屬性值的方法
     * @return
     */
    public String getName() {
        return name;
    }
    /**
     * 設置property元素的name屬性值的方法
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 取出property元素下面的子元素的方法,返回子元素的接口類型
     * @return
     */
    public LeafElement getLeafElement() {
        return leafElement;
    }
    /**
     * 設置property元素下面的子元素的方法
     * @param nodeElement
     */
    public void setLeafElement(LeafElement leafElement) {
        this.leafElement = leafElement;
    }
    /**
     * 構造方法將property元素的name值和下面的子元素保存到成員變量中
     * @param name
     * @param leafElement
     */
    public PropertyElement(String name, LeafElement leafElement) {
        this.name = name;
        this.leafElement = leafElement;
    }
}

接口中涉及到還有Autowire,這邊咱們在xml中新建一個autowire包而後新建一個接口Autowirethis

package com.tear.ioc.bean.xml.autowire;
/**
 * 這是表明自動裝配的接口
 * @author rongdi
 */
public interface Autowire {
    /**
     * 返回類中須要自動裝配的類型的值
     * @return
     */
    public String getType();
}

這裏可能不少人有疑問,autowire做爲bean的一個屬性表示自動裝配,爲何也定義成了接口,其實自動裝配有不少種,常見的spring裏面就有byName和byType,爲了體現面向對象的思想要麼定義成接口和子類,要麼直接定義成枚舉來區分,我這裏選擇了接口和子類方便處理,子類以下spa

package com.tear.ioc.bean.xml.autowire;

/**
 * 根據姓名自動裝配的類,實現自動裝配的接口
 * @author rongdi
 *
 */
public class ByNameAutowire implements Autowire {
    /**
     * 用一個構造方法保存傳入的自動裝配的類型值
     */
    private String type;
    public ByNameAutowire(String type) {
        this.type = type;
    }
    /**
     * 返回傳入的須要自動裝配的value值
     */
    public String getType() {
        return type;
    }
}
package com.tear.ioc.bean.xml.autowire;
/**
 * 這個類表明不自動裝配的類
 * @author rongdi
 *
 */
public class NoAutowire implements Autowire {
    
    @SuppressWarnings("unused")
    private String type;
    public NoAutowire(String type) {
        this.type = type;
    }
    /**
     * 直接返回no,表示不須要自動裝配
     */
    public String getType() {
        return "no";
    }

}

。有人可能會發現xml元素中可能出現這種片斷

<bean id="test2" class="com.xx.Test4">
     <constructor-arg>
         <value type="java.lang.String">xx</value>
     </constructor-arg>
     <constructor-arg>
         <value type="java.lang.String">12</value>
     </constructor-arg>
</bean>

怎麼接口中沒有提到有constructor-arg這種元素呢,其實這個元素本身沒有屬性,只是有一個子元素,咱們getConstructorArgsElements時徹底能夠直接去獲取他下面的value或者ref元素就能夠了。自此BeanElementParser接口中涉及到的bean咱們都介紹完了。咱們在看下實現類。

package com.tear.ioc.bean.xml.element.parser;

import java.util.ArrayList;
import java.util.List;

import org.dom4j.Element;

import com.tear.ioc.bean.xml.autowire.Autowire;
import com.tear.ioc.bean.xml.autowire.ByNameAutowire;
import com.tear.ioc.bean.xml.autowire.NoAutowire;
import com.tear.ioc.bean.xml.element.CollectionElement;
import com.tear.ioc.bean.xml.element.LeafElement;
import com.tear.ioc.bean.xml.element.PropertyElement;
import com.tear.ioc.bean.xml.element.RefElement;
import com.tear.ioc.bean.xml.element.ValueElement;

public class BeanElementParserImpl implements BeanElementParser {
    /**
     * 判斷某一個元素(bean)是否須要延遲加載
     */
    @Override
    public boolean isLazy(Element beanElement) {
        /**
         * 獲得該元素的lazy-init屬性
         */
        String elementLazy = this.getAttribute(beanElement, "lazy-init");
        /**
         * 獲得該元素的上層元素(beans)
         */
        Element parentElement = beanElement.getParent();
        /**
         * 獲得該元素的上層元素(beans)的default-lazy-init屬性
         */
        Boolean parentElementLazy = new Boolean(this.getAttribute(parentElement, "default-lazy-init"));
        if (parentElementLazy) {
            /**
             * 在根元素須要延遲加載的狀況下,子節點(bean)不須要延遲那麼不延遲加載
             */
            if ("false".equals(elementLazy)) {
                return false;
            }
            /**
             * 子節點須要延遲加載那麼就延遲加載
             */
            return true;
        } else {
            /**
             * 根節點不須要延遲加載的狀況下,子節點須要延遲加載那麼就延遲加載
             */
            if ("true".equals(elementLazy)) {
                return true;
            }
            /**
             * 根節點不須要延遲加載的狀況下,子節點也不須要延遲加載那麼就不延遲加載
             */
            return false;
        }
        
    }
    /**
     * 獲得bean元素下的全部的構造方法參數的元素constructor-arg
     */
    @SuppressWarnings("unchecked")
    @Override
    public List<Element> getConstructorArgsElements(Element element) {
        /**
         * 獲得該元素的全部子元素
         */
        List<Element> children = element.elements();
        /**
         * 定義一個保存所須要的元素的ArrayList集合
         */
        List<Element> result = new ArrayList<Element>();
        /**
         * 遍歷全部子元素,若果是constructor-arg元素直接加入到定義的ArrayList
         * 集合中
         */
        for (Element e : children) {
            if ("constructor-arg".equals(e.getName())) {
                result.add(e);
            }
        }
        /**
         * 返回全部的constructor-arg元素的集合
         */
        return result;
    }
    /**
     * 獲得元素的name屬性值
     */
    @Override
    public String getAttribute(Element element, String name) {
        String value = element.attributeValue(name);
        return value;
    }
    /**
     * 判斷元素(bean)是否爲單例的
     */
    @Override
    public boolean isSingleton(Element element) {
        /**
         * 若是元素的singleton屬性爲true(忽略大小寫),那麼返回true,
         * 若是是其餘的字符串或者是空則返回false
         */
        Boolean singleton = new Boolean(this.getAttribute(element, "singleton"));
        return singleton;
    }
    /**
     * 獲得某個元素(bean)下的全部property元素
     */
    @SuppressWarnings("unchecked")
    @Override
    public List<Element> getPropertyElements(Element element) {
        /**
         * 獲得該元素的全部子元素
         */
        List<Element> children = element.elements();
        /**
         * 定義一個保存所須要的元素的ArrayList集合
         */
        List<Element> result = new ArrayList<Element>();
    
        /**
         * 遍歷全部子元素,若果是property元素直接加入到定義的ArrayList
         * 集合中
         */
        for (Element e : children) {
            if("property".equals(e.getName())) {
                result.add(e);
            }
        }
        /**
         * 返回全部的Property元素的集合
         */
        return result;
    }
    /**
     * 獲得某個元素(bean)的傳入了自動裝配類型值的對象
     */
    @Override
    public Autowire getAutowire(Element element) {
        /**
         * 獲得某個元素(bean)的自動裝配的類型值
         */
        String type = this.getAttribute(element, "autowire");
        /**
         * 獲得該元素的父元素(beans)的默認的自動裝配類型值
         */
        String parentType = this.getAttribute(element.getParent(), "default-autowire");
        if ("no".equals(parentType)) {
            /**
             * 若是根節點不須要自動裝配,子節點須要以name自動裝配那麼返回一個以name自動裝配的
             * ByNameAutowire對象
             */
            if ("byName".equals(type)) {
                return new ByNameAutowire(type);
            }
            /**
             * 若是父節點和子節點都不須要自動裝配那麼就返回一個表示不須要自動裝配的NoAutowire對象
             */
            return new NoAutowire(type);
        } else if ("byName".equals(parentType)) {
            /**
             * 若是根節點須要自動裝配而子節點不須要自動裝配那麼返回一個表明不須要自動裝配的NoAutowire
             * 對象
             */
            if ("no".equals(type)) {
                return new NoAutowire(type);
            }
            /**
             * 若是根節點須要自動裝配子節點也須要自動裝配那麼返回一個表明須要以name自動裝配的
             *  ByNameAutowire對象
             */
            return new ByNameAutowire(type);
        }
        /**
         * 其餘狀況返回一個不須要自動裝配的對象
         */
        return new NoAutowire(type);
    }
    /**
     * 獲得全部的構造方法參數元素中的參數值,也就是ref或value元素
     */
    @SuppressWarnings("unchecked")
    @Override
    public List<LeafElement> getConstructorValue(Element element) {
        /**
         * 調用本類中的getConstructorElements方法取得所有的constructor-arg元素
         */
        List<Element> cons = this.getConstructorArgsElements(element);
        /**
         * 定義一個保存全部須要元素的ArrayList
         */
        List<LeafElement> result = new ArrayList<LeafElement>();
        /**
         * 遍歷全部的construct-arg元素
         */
        for (Element e : cons) {
            /**
             * 得到constructor-arg下的ref元素或者value元素的其中一個,dtd定義兩個元素
             * 只能有其中一個
             */
            List<Element> eles = e.elements();
            /**
             * 調用本類定義的getLeafElement方法得到構造參數元素下的ref或者value元素,封裝成
             * RefLeafElement或ValueLeafElement
             */
            LeafElement leafElement = this.getLeafElement(eles.get(0));
            /**
             * 將封裝好的RefLeafElement或ValueLeafElement元素加入到ArrayList中
             */
            result.add(leafElement);
        }
        /**
         * 返回NodeList的集合,裏面裝的是RefLeafElement或ValueLeafElement元素
         */
        return result;
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<PropertyElement> getPropertyValue(Element element) {
        /**
         * 獲得某一個元素下的全部property元素
         */
        List<Element> properties = this.getPropertyElements(element);
        /**
         * 定義一個ArrayList的集合準備保存所須要的Property元素
         */
        List<PropertyElement> result = new ArrayList<PropertyElement>();
        /**
         * 遍歷全部的Property元素
         */
        for (Element e : properties) {
            /**
             * 得到property下的ref元素或者value元素或者collection中的一個,由於三個元素是互斥的只能存在一個
             */
            List<Element> eles = e.elements();
            /**
             * 獲得List中的第一個ref元素或者是value元素
             */
            LeafElement leafElement = getLeafElement(eles.get(0));
            /**
             * 獲得property的name屬性的值
             */
            String propertyNameAtt = this.getAttribute(e, "name");
            /**
             * 將數據值和property元素的name屬性封裝成PropertyElement對象
             */
            PropertyElement pe = new PropertyElement(propertyNameAtt, leafElement);
            /**
             * 將該PreopertyElement元素加入到ArrayList中
             */
            result.add(pe);
        }
        /**
         * 返回PropertyElement元素的集合
         */
        return result;
    }
    /**
     * 該方法是根據傳過來的Element對象將其封裝成RefNodeElement或ValueNodeElement元素
     * 的對象
     * @param nodeElement
     * @return
     */
    private LeafElement getLeafElement(Element leafElement) {
        /**
         * 得到傳過來的Element元素的名字
         */
        String name = leafElement.getName();
        /**
         * 若是是value元素
         */
        if ("value".equals(name)) {
            
            /**
             *調用本類定義的方法getValueOfValueElement根據value的type類型返回一個
             *Object數組形式的value值,在構形成爲一個ValueElement對象返回
             */
            return new ValueElement(this.getValueOfValueElement(leafElement));
        }
        /**
         * 若是是ref元素
         */
        else if("ref".equals(name)) {
            /**
             * 返回一個將ref元素的bean屬性的值傳入的RefNodeElement對象
             */
            return new RefElement(this.getAttribute(leafElement, "bean"));
        }
        /**
         * 若是是collection元素
         */
        else if("collection".equals(name)) {
            /**
             * 調用本類的方法getCollectionElement獲得一個CollectionElement元素返回
             */
            return this.getCollectionElement(leafElement);
        }
        /**
         * 若是不是這兩種元素則返回null
         */
        return null;
    }
    /**
     * 這是一個ValueElement的值的Object數組
     * @param leafElement
     * @return
     */
    private Object getValueOfValueElement(Element leafElement) {
        /**
         * 獲得該value元素的type屬性的值
         */
        String typeName = leafElement.attributeValue("type");
        /**
         * 獲得該value元素的值(即value標籤之間的那個值)
         */
        String data = leafElement.getText();
        /**
         * 調用本類的方法返回一個ValueElement的值的數組形式
         */
        return IocUtil.getValue(typeName, data);
    }
    /**
     * 這是根據傳過來的一個leafElement元素構造一個CollectionElement元素返回
     * @param leafElement
     * @return
     */
    @SuppressWarnings("unchecked")
    private CollectionElement getCollectionElement(Element leafElement) {
        /**
         * 定義一個保存所需的LeafElement元素的集合
         */
        List<LeafElement> temp = new ArrayList<LeafElement>();
        /**
         * 先獲得該Collection元素的type屬性值
         */
        String typeName = leafElement.attributeValue("type");
        /**
         * 根據type類型new一個CollectionElement
         */
        CollectionElement ce = new CollectionElement(typeName);
        /**
         * 獲得該collection元素的全部子元素
         */
        List<Element> elements = leafElement.elements();
        /**
         * 遍歷全部的子元素
         */
        for(Element e:elements) {
            /**
             * 獲得Collection下子元素的元素名字
             */
            String tempName = e.getName();
            /**
             * 若是是value元素則調用對應方法獲得該元素的值,並根據該值new一個ValueElement並保存到temp集合中
             */
            if("value".equals(tempName)) {
                temp.add(new ValueElement(this.getValueOfValueElement(e)));
            }
            /**
             * 若是是ref元素則調用對應的方法獲得該元素的對應的值,並建立一個RefElement元素加到temp中
             */
            else if("ref".equals(tempName)) {
                temp.add(new RefElement(this.getAttribute(e, "bean")));
            }
        }
        /**
         * 將所獲得的ValueElement或Refelement元素加到CollectionElement的集合中去
         */
        ce.setList(temp);
        /**
         * 返回構造好的CollectionElement
         */
        return ce;
    }
    

}

上面代碼中涉及到了IocUtil類該類放在com.tear.ioc.util包下內容以下

package com.tear.ioc.util;
/**
 * 這是一個幫助類
 */
public class IocUtil {
    /**
     * 若是該類型是java中的幾個基本數據類型那麼返回它的類型,注意Integer.type就是得到他的class對象
     * 若是不是基礎類型則使用getClass()返回它的Class對象
     * @param obj
     * @return
     */
    public static Class<?> getClass(Object obj) {
        if (obj instanceof Integer) {
            return Integer.TYPE;
        } else if (obj instanceof Boolean) {
            return Boolean.TYPE;
        } else if (obj instanceof Long) {
            return Long.TYPE;
        } else if (obj instanceof Short) {
            return Short.TYPE;
        } else if (obj instanceof Double) {
            return Double.TYPE;
        } else if (obj instanceof Float) {
            return Float.TYPE;
        } else if (obj instanceof Character) {
            return Character.TYPE;
        } else if (obj instanceof Byte) {
            return Byte.TYPE;
        }
        return obj.getClass();
    }
    /**
     * 判斷className的類型是否爲基礎類型。如java.lang.Integer, 是的話將數據進行轉換
     * 成對應的類型該方法是供本類中的方法調用的,做用是根據type類型的值將對應的value數據轉換
     * 成對應的type類型的值
     * @param className
     * @param data
     * @return
     */
    public static Object getValue(String className, String data) {
        /**
         * 下面的全部if和else if都是判斷是不是java的8中基本數據類型的包裝類型
         */
        if (isType(className, "Integer")) {
            return Integer.parseInt(data);
        } else if (isType(className, "Boolean")) {
            return Boolean.valueOf(data);
        } else if (isType(className, "Long")) {
            return Long.valueOf(data);
        } else if (isType(className, "Short")) {
            return Short.valueOf(data);
        } else if (isType(className, "Double")) {
            return Double.valueOf(data);
        } else if (isType(className, "Float")) {
            return Float.valueOf(data);
        } else if (isType(className, "Character")) {
            /**
             * 若是是Character類型則取第一個字符
             */
            return data.charAt(0);
        } else if (isType(className, "Byte")) {
            return Byte.valueOf(data);
        } else {
            /**
             * 若是不是8種基本數據類型的包裝類那麼就是自定義的類了,直接返回該值
             */
            return data;
        }
    }
    /**
     * 該方法是判斷類名中是否含有對應的type字符串的方法,如判斷className:java.lang.Integer中
     * 是否包含Integer這樣就返回true,不包含則返回false,該方法是供上面的方法調用的
     * @param className
     * @param type
     * @return
     */
    private static boolean isType(String className, String type) {
        if (className.lastIndexOf(type) != -1)
            return true;
        return false;
    }
}

BeanElementParserImpl類中還涉及到了CollectionElement元素,該元素就是表示集合的元素list或者set以下xml片斷

<bean id="test3" class="com.xx.Test3" >
        <property name="list">
            <collection type="list">
                <value type="java.lang.String">zhangsan</value>
                <value type="java.lang.String">12</value>
            </collection>
        </property>
        <property name="set">
            <collection type="set">
                <value type="java.lang.String">lisi</value>
                <value type="java.lang.String">34</value>
            </collection>
        </property>
        <property name="refTest">
            <collection type="list">
                <ref bean="test1"></ref>
                <ref bean="test2"></ref>
            </collection>
        </property>
    </bean>

CollectionElement元素其實是包含了多個value或者ref元素CollectionElement以下

package com.tear.ioc.bean.xml.element;

import java.util.ArrayList;
import java.util.List;

/**
 * 這裏咱們使用的是組合模式,一個集合元素自己包含了多個葉子元素ref或者value
 * 自己能夠不用實現LeafElement可是這裏咱們爲了使CollectionElement和LeafElement
 * 以一樣的方式被處理因此咱們實現了LeafElement
 * @author rongdi
 */
public class CollectionElement implements LeafElement {
    private String type;
    private List<LeafElement> list;
    public void setList(List<LeafElement> list) {
        this.list = list;
    }
    public void add(LeafElement leafElement) {
        this.list.add(leafElement);
    }
    @Override
    public String getType() {
        return this.type;
    }
    public CollectionElement(String type) {
        this.type = type;
        
    }
    public List<LeafElement> getList() {
        return list;
    }
    @Override
    public Object[] getValue() {
        List<Object> value = new ArrayList<Object>();
        for(LeafElement le:this.getList()) {
            value.add(le.getValue());
        }
        return value.toArray();
    }

}

對於BeanElementParserImpl類中註釋已經寫的很清楚了,至於惟一一個值得注意的地方是getLeafElement(Element leafElement)這個方法else if("collection".equals(name))這裏就能夠看出來爲何CollectionElement要去使用組合模式實現LeafElement是爲了方便統一處理。PropertyElement和構造方法中均可能出現CollectionElement或者是ValueElement和RefElement若是不能統一成LeafElement去處理那就很麻煩了,具體見BeanElementParserImpl類中getConstructorValue方法和getPropertyValue方法,仔細看下就能發現這樣作的好處了。

使用測試用例進行測試test包下創建com.tear.ioc.xml.element.loader和com.tear.ioc.xml.element.parser

代碼分別以下

package com.tear.ioc.xml.element.loader;

import static org.junit.Assert.assertNotNull;

import java.util.Iterator;

import org.dom4j.Document;
import org.dom4j.Element;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.tear.ioc.bean.xml.document.XmlDocumentHolder;
import com.tear.ioc.bean.xml.element.loader.ElementLoader;
import com.tear.ioc.bean.xml.element.loader.ElementLoaderImpl;

public class ElementLoaderImplTest {
    XmlDocumentHolder xmlHolder;
    ElementLoader elementLoader;
    @Before
    public void setUp() throws Exception {
        xmlHolder = new XmlDocumentHolder();
        elementLoader = new ElementLoaderImpl();
        
    }

    @After
    public void tearDown() throws Exception {
        xmlHolder = null;
        elementLoader = null;
    }

    @Test
    public void testAddElements() {
        String filePath = "test/resources/element/ElementLoaderImpl.xml";
        Document document = xmlHolder.getDocument(filePath);
        assertNotNull(document);
        elementLoader.addBeanElements(document);
        Element e = elementLoader.getBeanElement("test1");
        assertNotNull(e);
        for(Iterator iter = elementLoader.getBeanElements().iterator();iter.hasNext();){
            System.out.println(iter.next());
        }
    }
}
package com.tear.ioc.xml.element.parser;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.List;

import org.dom4j.Document;
import org.dom4j.Element;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.tear.ioc.bean.xml.autowire.Autowire;
import com.tear.ioc.bean.xml.document.XmlDocumentHolder;
import com.tear.ioc.bean.xml.element.LeafElement;
import com.tear.ioc.bean.xml.element.PropertyElement;
import com.tear.ioc.bean.xml.element.RefElement;
import com.tear.ioc.bean.xml.element.ValueElement;
import com.tear.ioc.bean.xml.element.loader.ElementLoader;
import com.tear.ioc.bean.xml.element.loader.ElementLoaderImpl;
import com.tear.ioc.bean.xml.element.parser.BeanElementParser;
import com.tear.ioc.bean.xml.element.parser.BeanElementParserImpl;

public class ElementParserImplTest {
    private XmlDocumentHolder xmlHolder;
    
    private ElementLoader elementLoader;
        
    private BeanElementParser parser;
    @Before
    public void setUp() throws Exception {
        xmlHolder = new XmlDocumentHolder();
        elementLoader = new ElementLoaderImpl();
        String filePath = "test/resources/element/elementParserImpl.xml";
        Document doc = xmlHolder.getDocument(filePath);
        elementLoader.addBeanElements(doc);
        parser = new BeanElementParserImpl();
    }

    @After
    public void tearDown() throws Exception {
        xmlHolder = null;
        elementLoader = null;
    }

    @Test
    public void testIsLazy() {
    
        //第一個元素
        Element e = elementLoader.getBeanElement("test1-1");
        boolean result = parser.isLazy(e);
        assertTrue(result);
        //第二個元素
        e = elementLoader.getBeanElement("test1-2");
        result = parser.isLazy(e);
        assertFalse(result);
        //第三個元素
        e = elementLoader.getBeanElement("test1-3");
        result = parser.isLazy(e);
        assertFalse(result);
    }

    @Test
    public void testGetConstructorElements() {
        Element e = elementLoader.getBeanElement("test2");
        List<Element> constructorElements = parser.getConstructorArgsElements(e);
        assertEquals(constructorElements.size(), 2);
    }

    @Test
    public void testGetAttribute() {
        Element e = elementLoader.getBeanElement("test3");
        String value =  parser.getAttribute(e, "class");
        assertEquals(value, "com.tear.Test5");
    }

    @Test
    public void testIsSingleton() {
        Element e = elementLoader.getBeanElement("test4-1");
        boolean result = parser.isSingleton(e);
        assertFalse(result);
        
        e = elementLoader.getBeanElement("test4-2");
        result = parser.isSingleton(e);
        assertTrue(result);
    }

    @Test
    public void testGetPropertyElements() {
        Element e = elementLoader.getBeanElement("test6");
        List<Element> elements = parser.getPropertyElements(e);
        assertEquals(elements.size(), 2);
    }

    @Test
    public void testGetAutowire() {
        Element e = elementLoader.getBeanElement("test10-1");
        assertEquals(parser.getAttribute(e, "id"), "test10-1");
        Autowire result = parser.getAutowire(e);
        assertEquals(result.getType(), "byName");
        
        e = elementLoader.getBeanElement("test10-2");
        result = parser.getAutowire(e);
        assertEquals(result.getType(), "no");
        
        e = elementLoader.getBeanElement("test10-3");
        result = parser.getAutowire(e);
        assertEquals(result.getType(), "no");
    }

    @Test
    public void testGetConstructorValue() {
        Element e = elementLoader.getBeanElement("test11");
        assertEquals(parser.getAttribute(e, "id"), "test11");
        List<LeafElement> result = parser.getConstructorValue(e);
        assertEquals(result.size(), 2);
        
        ValueElement ve1 = (ValueElement)result.get(0);
        System.out.println(ve1.getValue());
        assertEquals((String)ve1.getValue(),"tear");
        
        RefElement re = (RefElement)result.get(1);
        assertEquals((String)re.getValue(), "test11");
        
    }

    @Test
    public void testGetPropertyValue() {
        Element e = elementLoader.getBeanElement("test12");
        List<PropertyElement> eles = parser.getPropertyValue(e);
        assertEquals(eles.size(), 4);
        System.out.println(eles.get(0).getLeafElement().getValue());
        assertEquals(eles.get(0).getName(), "property1");
        assertEquals(eles.get(0).getLeafElement().getValue(), "tear");
        assertEquals(eles.get(0).getLeafElement().getType(), "value");
        System.out.println(eles.get(3).getLeafElement());
        System.out.println(eles.get(3).getLeafElement().getType());
        Object[] obj = (Object[])eles.get(3).getLeafElement().getValue();
        System.out.println(obj[0]);
        System.out.println(obj[1]);
    
    }

}

測試用到的xml文件放在test下resources.element包下elementLoaderImpl.xml文件內容以下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//RONGDI//DTD BEAN//CN" 
    "http://www.cnblogs.com/rongdi/beans.dtd">
<beans>
    <bean id="test1" class="test1"></bean>
    <bean id="test2" class="test2"></bean>
    <bean id="test3" class="test3"></bean>
</beans>

elementParserImpl.xml文件以下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//RONGDI//DTD BEAN//CN" 
    "http://www.cnblogs.com/rongdi/beans.dtd">
<beans>
    <!-- isLazy-->
    <bean id="test1-1" class="com.tear.Test1" lazy-init="true"></bean>
    <bean id="test1-2" class="com.tear.Test2" lazy-init="default"></bean>
    <bean id="test1-3" class="com.tear.Test3" lazy-init="false"></bean>
    <!-- getConstructorElements-->
    <bean id="test2" class="com.tear.Test4">
        <constructor-arg>
            <value type="java.lang.String">tear</value>
        </constructor-arg>
        <constructor-arg>
            <value type="java.lang.String">1989229</value>
        </constructor-arg>
    </bean>
    <!-- getAttribute -->
    <bean id="test3" class="com.tear.Test5"></bean>
    <!-- isSingleton -->
    <bean id="test4-1" class="com.tear.Test6" singleton="false"></bean>
    <bean id="test4-2" class="com.tear.Test7"></bean>
    <!-- getConstructorArgs -->
    <bean id="test5" class="com.tear.Test8">
        <constructor-arg>
            <value type="java.lang.String">wstear</value>
        </constructor-arg>
        <constructor-arg>
            <value type="java.lang.String">1989229</value>
        </constructor-arg>
    </bean>
    <!-- getPropertyElements-->
    <bean id="test6" class="com.tear.Test9">
        <property name="test1">
            <ref bean="test1"/>
        </property>
        <property name="test2">
            <ref bean="test2"/>
        </property>
    </bean>
    <!-- getPropertyValues -->
    <bean id="test7" class="com.tear.Test10">
        <property name="test1">
            <value type="java.lang.String">wstear</value>
        </property>
        <property name="test2">
            <value type="java.lang.String">1989229</value>
        </property>
    </bean>
    <!-- getPropertyRef -->
    <bean id="test8" class="com.tear.Test11">
        <property name="test1">
            <ref bean="test1"/>
        </property>
        <property name="test2">
            <ref bean="test2"/>
        </property>
    </bean>
    
    <!-- getConstructorRef-->
    <bean id="test9" class="com.tear.Test12">
        <constructor-arg>
            <ref bean="test1"/>
        </constructor-arg>
        <constructor-arg>
            <ref bean="test2"/>
        </constructor-arg>
    </bean>

    <!-- isAutowire -->
    <bean id="test10-1" class="com.tear.Test13" autowire="byName">
    </bean>
    <bean id="test10-2" class="com.tear.Test14" autowire="no">
    </bean>
    <bean id="test10-3" class="com.tear.Test15" autowire="default">
    </bean>
    <bean id="test11" class="com.tear.Test11">
        <constructor-arg>
            <value type="java.lang.String">tear</value>
        </constructor-arg>
        <constructor-arg>
            <ref bean="test11"/>
        </constructor-arg>
    </bean>

    
    <!-- getPropertyValue -->
    <bean id="test12" class="com.tear.Test17">
        <property name="property1">
            <value type="java.lang.String">tear</value>
        </property>
        <property name="property2">
            <ref bean="test13"/>
        </property>
        <property name="property3">
            <value type="java.lang.Integer">22</value>
        </property>
        <property name="property4">
            <collection type="list">
                <value type="java.lang.Integer">1212</value>
                <value type="java.lang.String">tear</value>
            </collection>
        </property>
    </bean>
    <bean class="com.tear.Test18" id="test13"></bean>
</beans>

自此咱們已經完成了對document中的全部與業務相關的元素的解析。方便下一層去處理。

  下次再見,若是有任何問題能夠直接留言,我會在看到後第一時間回覆,詳細代碼見百度雲地址:http://pan.baidu.com/s/1bncXTM3

相關文章
相關標籤/搜索