Spring中的Object/XML映射詳解
Spring作為Java應用程序框架,已在Java開發社區中得到廣泛使用,SpringSource近日發布了最新版本Spring 3.0.1版本。文章主要針對Spring中的Object/XML映射,分析使用Object/XML映射的特性與優勢。
Spring以其流行的科技詞匯而著名,比如“dependencyinjection(依賴項注入)”、“inversionofcontrol(控制反轉)”和“aspect-orientedprogramming(面向方面編程)”等。它還支持Model-View-Controller(MVC)模式,很好地兼容用于數據訪問的各種數據庫驅動程序。
另外,它支持事務處理、單元測試、批處理和安全性。鑒于Spring的良好聲譽和悠久歷史,它通常是應用程序快速開發的首選框架。但是,最大的好處也許是:Spring是免費的。
Object/XML映射是什么?
Spring 3.0的一個新特性是O/XMapper。O/X映射器這個概念并不新鮮,O代表Object,X代表XML。它的目的是在Java對象(幾乎總是一個plainoldJavaobject,或簡寫為POJO)和XML文檔之間來回轉換。
例如,您可能有一個帶有幾個屬性的簡單bean,且您的業務需要將那個Java對象轉換為一個XML文檔。Spring的O/XMapper能夠為您解決那個問題。如果反過來,您需要將一個XML文檔轉換為一個簡單Javabean,Spring的O/XMapper也能勝任,有一點需要注意:SpringO/XMapper只是定義由流行的第三方框架實現的統一的界面。要利用Spring的O/X功能,您需要一個在Java對象和XML之間來回轉換的實用程序。Castor就是這樣一個流行的第三方工具,本文將使用這個工具。其他這樣的工具包括XMLBeans、JavaArchitectureforXMLBinding(JAXB)、JiBX和XStream。
編組和解組
進行O/X映射時,您經常會看到編組(marshalling)和解組(unmarshalling)這兩個術語。編組指將Javabean轉換成XML文檔的過程,這意味著Javabean的所有字段和字段值都將作為XML元素或屬性填充到XML文件中。有時,編組也稱為序列化(serializing)。
如您所料,解組是與編組完全相反的過程,即將XML文檔轉換為Javabean,這意味著XML文檔的所有元素或屬性都作為Java字段填充到Javabean中。有時,解組也稱為反序列化(deserializing)。
使用Spring的O/XMapper的好處
使用Spring的O/XMapper的一個最直接的好處是可以通過利用Spring框架的其他特性簡化配置。Spring的bean庫支持將實例化的O/X編組器注入(即前面提到過的“依賴項注入”)使用那些編組器的對象。重申一遍,這將加快應用程序開發和部署。
遵循堅實的面向對象的設計實踐,Spring Object/XML框架只定義兩個接口:Marshaller和Unmarshaller,它們用于執行O/X功能,這是使用這個框架的另一個重大好處。這些接口的實現完全對獨立開發人員開放,開發人員可以輕松切換它們而無需修改代碼。例如,如果您一開始使用Castor進行O/X轉換,但后來發現它缺乏您需要的某個功能,這時您可以切換到XMLBeans而無需任何代碼更改。唯一需要做的就是更改Spring配置文件以使用新的Object/XML框架。
使用Spring的Object/XML映射的另一個好處是統一的異常層次結構。Spring框架遵循使用它的數據訪問模塊建立的模式,方法是將原始異常對象包裝到Spring自身專為O/XMapper建立的運行時異常中。由于第三方提供商拋出的原始異常被包裝到Spring運行時異常中,您能夠查明出現異常的根本原因。您也不必費心修改代碼以捕獲異常,因為異常已包裝到一個運行時異常中。以下幾個運行時異常擴展了基礎異常XMLMappingException:GenericMarshallingFailureException、ValidationFailureException、MarshallingFailureException和UnmarshallingFailureException。 #p#
一個簡單的演示
現在您已經了解了Spring的O/XMapper的背景和基礎知識,可以檢驗它的使用方法了。在本文中,您首先創建一個簡單的Spring應用程序,該程序獨立于任何JavaEnterprise依賴項。然后,您創建一個簡單的Java類,它訪問Spring的配置文件來實例化該類并注入O/X依賴項。參見下載部分獲取所有源代碼文件(包括配置文件)的鏈接。
編碼
首先應該注意Spring配置文件。清單1是應用程序用于執行編組和解組操作的配置文件。注意,這個文件必須在運行時位于類路徑中,清單1.配置文件:
- <beansxmlnsbeansxmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
- <beanidbeanid="oxmExample"class="com.xyz.OXMExample">
- <propertynamepropertyname="marshaller"ref="castorMarshaller"/>
- <propertynamepropertyname="unmarshaller"ref="castorMarshaller"/>
- </bean>
- <beanidbeanid="castorMarshaller"class="org.springframework.oxm.castor.CastorMarshaller">
- <propertynamepropertyname="mappingLocation"value="classpath:mapping.xml"/>
- </bean>
- </beans>
如您所見,這個配置文件只定義了兩個bean,這是為了簡便起見。第一個bean是用于執行演示的類:com.xyz.OXMExample。與該類關聯的兩個屬性使用依賴項注入,它們都使用castorMarshallerbean的一個實例注入。這是在Spring框架中定義bean的標準方法,經驗豐富的Spring開發人員很快就會意識到這一點。
另一個bean是castorMarshallerbean本身,它是org.springframework.oxm.castor.CastorMarshaller的一個實例,org.springframework.oxm.castor.CastorMarshaller主要用于包裝Castor框架。如前所述,使用Spring的Object/XML功能需要使用一個第三方O/X框架。在本例中,這個第三方產品是Castor。還要注意,有一個屬性使用castorMarshaller定義,那是用于在Javabean和XML輸出之間來回映射的映射文件。這個文件稱為mapping.xml,它必須在運行時位于類路徑中。我將稍后解釋mapping.xml文件的內容。清單2實際執行O/X映射器的代碼的部分清單。它是一個簡單的Java類,清單2.OXMExample類:
- publicclassOXMExample{
- privatestaticfinalStringFILE_NAME="simplebean.xml";
- privateSimpleBeansimpleBean;
- privateMarshallermarshaller;
- privateUnmarshallerunmarshaller;
- publicvoidsetMarshaller(Marshallermarshaller){
- this.marshaller=marshaller;
- }
- publicvoidsetUnmarshaller(Unmarshallerunmarshaller){
- this.unmarshaller=unmarshaller;
- }
- publicvoidsaveSimpleBean()throwsIOException{
- FileOutputStreamos=null;
- try{
- os=newFileOutputStream(FILE_NAME);
- this.marshaller.marshal(simpleBean,newStreamResult(os));
- }finally{
- if(os!=null){
- os.close();
- }
- }
- }
- publicvoidloadSimpleBean()throwsIOException{
- FileInputStreamis=null;
- try{
- is=newFileInputStream(FILE_NAME);
- this.simpleBean
- =(SimpleBean)this.unmarshaller.unmarshal(newStreamSource(is));
- }finally{
- if(is!=null){
- is.close();
- }
- }
- }
- publicstaticvoidmain(String[]args)throwsIOException{
- ApplicationContextappContext
- =newClassPathXmlApplicationContext("applicationContext.xml");
- OXMExampleex=(OXMExample)appContext.getBean("oxmExample");
- ex.go();
- }
- privatevoidgo()throwsIOException{
- simpleBean=getSimpleBean();
- saveSimpleBean();
- loadSimpleBean();
- System.out.println("name:"+simpleBean.getName());
- System.out.println("jobdescription:"+simpleBean.getJobDescription());
- System.out.println("age:"+simpleBean.getAge());
- System.out.println("executive:"+simpleBean.isExecutive());
- }
- privateSimpleBeangetSimpleBean(){
- SimpleBeansimpleBean=newSimpleBean();
- simpleBean.setAge(35);
- simpleBean.setExecutive(false);
- simpleBean.setJobDescription("Janitor");
- simpleBean.setName("MisterJones");
- returnsimpleBean;
- }
- }
要解釋清單2,必須首先介紹main方法,因為該方法將先執行。然后再接著介紹清單2,首先,在main方法中,您的代碼捕獲Spring應用程序的上下文,就是您在清單1中看到的配置文件。這個文件必須在類路徑中,否則運行代碼將產生一個異常。 #p#
當您獲得應用程序上下文時,OXMExample的一個實例從該配置文件中提供的定義創建。注意,這個bean在代碼中的名稱(oxmExample)與配置文件中定義的名稱(見清單1)一致。創建OXMExample的一個實例后,調用go()方法。這有點反常,因為Spring框架實例化一個已經從命令行運行的對象,但那只是為了實現演示目的而進行的簡化。go()方法在打印結果數據前完成3個任務:
1.創建SimpleBean的一個實例。
2.編組該實例。
3.解組從編組創建的XML文檔。
您使用getSimpleBean()方法實例化一個包含一個虛擬員工的信息的SimpleBean對象。這個信息包含年齡(一個整數)、工作描述(一個字符串)、姓名(一個字符串)和該員工是否是執行官(一個布爾型)。您使用測試數據和返回調用者的返回對象(在本例中為go()方法)填充字段。您在編組發生時將這個bean寫入一個XML文件,在解組發生時讀取那個XML文件的內容。
saveSimpleBean()方法執行編組。首先,您獲得一個指向simplebean.xml的對象,然后,您使用編組器對象(通過Spring的依賴項注入實例化)調用marshal方法。這個方法需要兩個參數:
◆要被編組的對象(本例中為SimpleBean實例)
◆一個StreamResult對象,它基本上表示一個XML輸出抽象
loadSimpleBean()方法執行解組。首先,您獲取一個指向simplebean.xml的FileInputStream對象,然后,您使用解組器對象(通過Spring的依賴項注入實例化)調用unmarshal方法。唯一需要的參數是一個包裝FileInputStream對象的StreamSource對象。注意,解組將創建一個泛型對象,因此您必須將其顯式設置為SimpleBean類型。
即使這個類和Spring配置文件已經就緒,您也還沒有準備好運行這段代碼。還記得清單1中的映射文件嗎?您還需要定義那個映射文件。定義代碼如清單3所示,而且,再說一遍,它也必須在運行時位于類路徑中。清單3.mapping.xml文件:
- <mapping>
- <classnameclassname="com.xyz.SimpleBean">
- <map-toxmlmap-toxml="simplebean"/>
- <fieldnamefieldname="age"type="integer">
- <bind-xmlnamebind-xmlname="age"node="element"/>
- </field>
- <fieldnamefieldname="executive"type="boolean">
- <bind-xmlnamebind-xmlname="is-executive"node="element"/>
- </field>
- <fieldnamefieldname="jobDescription"type="string">
- <bind-xmlnamebind-xmlname="job"node="element"/>
- </field>
- <fieldnamefieldname="name"type="string">
- <bind-xmlnamebind-xmlname="name"node="element"/>
- </field>
- </class>
- </mapping>
清單3中的映射文件特定于Object/XML映射的Castor實現。第一個元素(class)定義要映射到一個XML輸出的類。您必須指定完整路徑,map-to元素提供XML文件的根元素的名稱。這很重要,因為XML規范規定,每個XML文件必須有一個根元素。
每個field元素都將被映射到SimpleBean類中的一個特定字段。每個field元素的bind-xml子元素用于指定關于該字段的特定于XML的信息,如對應的XML元素的名稱,每個字段的值應該是一個元素值還是一個屬性值。如您所見,在本例中,所有值都是元素值。
測試
盡管代碼已經編寫完成,但在執行這個應用程序之前,您必須處理一些依賴項,特定于Spring的依賴項有:
- org.springframework.asm-3.0.0.M4.jar
- org.springframework.beans-3.0.0.M4.jar
- org.springframework.context-3.0.0.M4.jar
- org.springframework.core-3.0.0.M4.jar
- org.springframework.expression-3.0.0.M4.jar
- org.springframework.oxm-3.0.0.M4.jar
特定于Castor的依賴項有:
- castor-1.3-core.jar
- castor-1.3-xml.jar
您還需要commons-logging-1.1.1.jar和log4j-1.2.15.jar,因為Spring框架需要它們,所有這些JavaArchive(JAR)文件必須在運行時位于類路徑中。如果您在沒有這些依賴項的情況下試圖運行代碼,您很可能會收到一個異常,指出某個類沒有找到。如果遇到這種情況,只需雙擊您的類路徑,確保所有的必要依賴項已就緒。事實上,要成功編譯這段代碼,您需要大部分JAR文件。
您可以使用您鐘愛的IDE或只是使用命令行來運行OXMExample.class。要從命令行運行,只需從您的工作目錄輸入java-cp[classpath]OXMExample,這里的[classpath]是指向剛才提到的所有依賴項(JAR文件和配置文件)的類路徑。首次運行該程序后,一個名為simplebean.xml的新文件將出現在您的工作目錄中。該文件的內容應該如清單4所示,清單4.simplebean.xml文件:
- <?xmlversionxmlversion="1.0"encoding="UTF-8"?>
- <simplebean>
- <age>35</age>
- <is-executive>false</is-executive>
- <job>Janitor</job>
- <name>MisterJones</name>
- </simplebean>
清單4顯示了來自應用程序的編組端的輸出,而清單5則顯示來自應用程序的解組端的結果,這些結果將在您的控制臺中顯示,清單5.解組輸出:
- name:MisterJones
- jobdescription:Janitor
- age:35
- executive:false
現在,您已經成功地完成了您的首次SpringO/X映射測試,現在最好做開發人員應該做的工作:修改代碼。向類添加字段并將它們映射到XML文件。刪除一些字段并將它們從XML文件中移除。參考Castor文檔,嘗試一些更復雜的工作,比如嵌套元素。您可以隨心所欲地嘗試各種可能性。
結束語
Spring的O/X映射接口是Spring框架的強大特性。借助它,您不僅可以將XML文檔轉換為Java對象,還可以將Java對象轉換為XML文檔。它利用Spring的一個關鍵優勢:依賴項注入。通過結合使用依賴項注入和Spring的O/XMapper,您可以輕松開發一個解決方案,該方案可以使用任一O/X實現,比如Castor、XBeans、JiBX、JAXB和XStream。由于各個特定實現是Spring強大的InversionofControl容器的一部分,開發人員可以在多個特定O/X實現之間輕松切換而無需修改代碼。
Spring的O/XMapper還向開發人員提供一個統一的異常層次結構,這意味著不管您使用哪個第三方實現,拋出的運行時異常都是相同的。再強調一次,這將有利于在多個O/X供應商之間切換,在Java開發社區中,提供XML支持的Java應用程序非常熱門并且Spring框架被廣泛使用,因此Spring的O/XMapper將受到全世界Java應用程序開發人員的歡迎。
【編輯推薦】
- Spring 3.0發布 全面支持RESTful架構
- 使用 Spring Framework 設計和開發 SCA 組件
- 愛恨交加:OSGi的Spring和EJB之路?
- OSGi與Spring DM:使用Spring DataSource
- Spring仍然輕量么?談SpringSource的發展戰略