萬事開頭難,上篇已經起了一個頭,之后的事情相對就簡單了。上次定義了框架所需的dtd也就是規定了xml中該怎么寫,有哪些元素。並且我們也讓dtd和xml綁定在了一起,使dtd對xml的格式進行校驗,並且在DocumentHolder中提供了根據xml文件路徑獲取xml文件的Document對象。這次我們應該把重點轉到從document對象中拿到我們所需要的標簽Element元素了。
一步步來,我們有了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如下
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,小伙伴們可以自己提供類似的方法,這里我們忽略了。
實現類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片段:
<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代碼如下
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包然后新建一個接口Autowire
package com.tear.ioc.bean.xml.autowire; /** * 這是代表自動裝配的接口 * @author rongdi */ public interface Autowire { /** * 返回類中需要自動裝配的類型的值 * @return */ public String getType(); }
這里可能很多人有疑問,autowire作為bean的一個屬性表示自動裝配,為什么也定義成了接口,其實自動裝配有很多種,常見的spring里面就有byName和byType,為了體現面向對象的思想要么定義成接口和子類,要么直接定義成枚舉來區分,我這里選擇了接口和子類方便處理,子類如下
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