摘 要: 介紹了JAXM結構,并利用其特點構建了不使用消息接發(fā)提供者的Web服務應用,分析了基于JAXM設計的體系結構和設計模式。
關鍵詞: JAXM規(guī)范 SAAJ包 SOAP規(guī)范 Web服務
JAXM(Java API for XML Messaging)是基于SOAP1.1規(guī)范并帶有Attachments的SOAP規(guī)范,它定義了一個能夠與XML消息交換的基本框架。JAXM提供了一種能夠在Java平臺上通過Internet發(fā)送XML文檔的標準方法,使得開發(fā)者可以使用Java平臺進行XML消息收發(fā)。而大多數(shù)的Web服務都是由簡單的消息交換組成,對于有些Web服務,直接在低級別的消息層編程通常是很有用的。JAXM提供了使XML數(shù)據(jù)能夠在二個應用之間互操作的框架,允許在二個獨立的Web服務之間完成全部XML文件的傳輸,而SOAP提供了在二個應用之間傳輸消息的底層格式。
1 JAXM相關概念
完整的JAXM API存在于javax.xml.soap和javax.xml.messaging二個包中。javax.xml.soap是用于接發(fā)SOAP消息的基本包,主要包含了發(fā)送帶有附件的SOAP消息的API(SOAP with Attachments API for Java,SAAJ)。這個包包含所有發(fā)送請求-響應消息所必需的API。javax.xml.messaging包含了使用消息接發(fā)提供者必須的API,因此能夠發(fā)送單向消息?,F(xiàn)在SAAJ不再依賴于javax.xml.messaging包,可以獨立使用。在JAXM1.1規(guī)范中定義的javax.xml.messaging包保持了對java.xml.soap包的依賴。
JAXM消息遵循SOAP標準,規(guī)定了消息的格式。通過JAXM API可以方便地創(chuàng)建遵從SOAP規(guī)范的XML消息。有二類SOAP消息,一類是帶有附件的消息,另一類是沒有附件的消息。SOAP消息都是通過連接進行接發(fā)的,有二種類型的連接,分別由JAXM API提供的類和接口來表示。javax.xml.soap.SOAPConnection表示了消息發(fā)送者到接收者的直接連接,這種類型的連接是點對點的,即使不在Servlet或者J2EE容器里也能使用。這種類型的消息接發(fā)又稱為請求-響應消息接發(fā)。javax.xml.messaging.ProviderConnection表示了到消息接發(fā)提供者的連接,這種連接方式需要消息發(fā)送者和消息使用者通過消息提供者來交互。
2 使用JAXM建立Web服務消息接發(fā)
JAXM客戶端可以使用消息接發(fā)提供者,也可以不用。沒有使用消息接發(fā)提供者的應用程序被限制只能承擔客戶端的角色,只能發(fā)送請求-響應消息。下面介紹建立不使用消息接發(fā)提供者的Web服務消息接發(fā),即點對點的請求-響應消息接發(fā)。
(1)獲得連接。任何一個JAXM客戶端需要完成的第一件事是獲得連接。當前客戶端使用SOAPConnection對象創(chuàng)建連接,使用SoapConnection對象發(fā)送的消息直接從發(fā)送者到發(fā)送者指定的URL,示例如下:
SOAPConnectionFactory scf=SOAPConnectionFactory.
newInstance( );
SOAPConnection con=scf.createConnection( );
(2)創(chuàng)建消息。生成消息可以使用SAAJ API提供的MessageFactory類的默認實現(xiàn)。
MessageFactory mf=MessageFactory.newInstance( );
SOAPMessage msg=mf.createMessage( );
由messageFactory創(chuàng)建的所有SOAPMessage對象都是基本SOAP消息,這意味著它們沒有預定義的頭部。JAXM所具有的靈活性之一就是它允許SOAP頭部有特殊的用途。例如,像ebXML這樣的一些協(xié)議可以建立在SOAP消息發(fā)送協(xié)議之上,以便提供附加頭部的實現(xiàn),這樣就獲得了附加的功能。
(3)向消息添加內容??梢韵騍OAPPart對象以及一個或多個AttachmentPart對象添加內容,也可以向消息的這二個部分都添加內容。為了向消息體添加內容,需創(chuàng)建一個SOAPBodyElement對象并添加一個使用SOAPElement.addTextNode方法建立的XML元素。
(4)發(fā)送消息。一旦填充了一個SOAPMessage對象,就可以發(fā)送此對象了。單獨客戶端使用SOAPConnection的call方法來發(fā)送消息。該方法發(fā)送完消息之后就將自己阻塞起來,直到收到響應為止。傳給call方法的參數(shù)中,一個是要發(fā)送的消息,還有一個是URL對象,該對象包含了接收者端點的URL。
(5)從響應消息中檢索內容。客戶端使用onMessage方法檢索消息內容??蛻舳送ㄟ^消息得到envelope,再通過envelope得到body,從而訪問SOAPBody對象。
3 使用JAXM構建Web服務應用
下面使用JAXM 構建對外提供話費查詢的Web服務。由于客戶端是Web服務的消費者,所以JAXM客戶端不需要消息接發(fā)提供者,使用點對點的請求-響應消息接發(fā)即可。話費查詢服務系統(tǒng)體系結構如圖1所示。
客戶端可以是一般的Java GUI程序(當然也可以是JSP、Servlet等),客戶端通過SOAP消息與Servlet容器中運行的JAXM Servlet進行交互。JAXM Servlet是服務提供者,EJB容器里運行的是業(yè)務組件,為JAXM Servlet提供服務。

系統(tǒng)為客戶端提供了三種查詢服務:每月匯總查詢、話費詳單查詢、即時詳單查詢。這三種服務分別對應服務端的三個JAXM Servlet實現(xiàn):TotalMonth,每月匯總查詢;DetailMonth,話費詳單查詢;PrestentDetail,即時詳單查詢。
(1)數(shù)據(jù)模型。在數(shù)據(jù)庫中保存每個用戶的話費信息。為了便于傳輸數(shù)據(jù),減少遠程調用的次數(shù),特別設計了值對象TelExpVA來代表話費信息。值對象設計模式在J2EE模式中大量使用。JAXM Servlet和EJB組件之間傳遞數(shù)據(jù)就是通過對象來傳遞的。這個對象是包含有TelExpVA實例的java.util.Collection。但是JAXM和客戶端是通過SOAP消息來傳遞的(也可以使用序列化的對象作為附件發(fā)送)。為了傳輸話費信息,還需要定義相對應的DTD或者schema。
(2)業(yè)務邏輯。業(yè)務層是EJB組件,使用了二個EJB組件,一個是TelExpServiceFacadeEJB,它是一個有狀態(tài)會話Bean;另一個是TelExpEntityEJB,它是一個實體Bean,代表了持久數(shù)據(jù)。TelExpServiceFacadeEJB是會話門面,JAXM Servlet通過它來和TelExpEntityEJB交互。
(3)JAXM服務端。JAXM服務端Servlet處理消息的步驟是:獲得消息(onMessage),讀取消息中需要的參數(shù),利用參數(shù)調用對應的業(yè)務處理,構建響應SOAP消息,返回處理后的消息。
在JAXM 服務端設計了三個服務JAXM Servlet,分別對應三個查詢用例,其關系如圖2所示。

由于使用了點對點的消息模型,服務端需要實現(xiàn)javax.xml.messaging.ReqRespListener接口,并且需要繼承javax.xml.messaging.JAXMServlet類。onMessage方法就是當Servlet接收到SOAPMessage時激發(fā)的方法,通過此方法對外界提供服務。每個JAXM Servlet都有一個onMessage方法。
(4)客戶端。最終客戶端是一個叫TelExpClientGUI的圖形界面程序,它并不直接與SOAP消息打交道,而是通過JAXMDelegate類與服務端JAXM Servlet進行交互。另外,還設計了一個BookBusiness接口。JAXMDelegate實現(xiàn)了BookBusiness接口,BookClientGUI持有BookBusiness的實例,它通過這個實例獲得信息。BookBusiness返回的信息都是java.util.Collection,它是BookClientGUI和JAXMDelegate通信的橋梁。
(5)使用XML業(yè)務代表的模式。用JAXM進行Web服務開發(fā)還不普遍,相應的設計模式的探討還較少,它的設計模式和J2EE平臺其他組件的設計模式基本一致。但它有自己的特點,如客戶端和服務端是通過SOAP消息進行通信,這與J2EE平臺的其他組件之間的通信不同。在JAXM編程中,為了實現(xiàn)數(shù)據(jù)(這里是SOAP消息)的一致返回,可以使用XML業(yè)務代表的模式。用JAXM進行編程時,數(shù)據(jù)傳遞的特點如圖3所示。

客戶端最終要使用的數(shù)據(jù)是Java對象或者Java的基本數(shù)據(jù)類型,而客戶端和服務端的通信是通過SOAP消息格式來傳輸,而在服務端要調用業(yè)務邏輯,必須使用Java對象或者是Java基本數(shù)據(jù)類型,這使數(shù)據(jù)的傳輸和數(shù)據(jù)的使用出現(xiàn)矛盾。為解決矛盾,可以使用數(shù)據(jù)轉換器來轉換數(shù)據(jù),以降低層之間的耦合度,使數(shù)據(jù)易于處理。當客戶端要發(fā)送數(shù)據(jù)時,使用數(shù)據(jù)轉換器把請求數(shù)據(jù)轉換為SOAP消息格式。當在服務端調用業(yè)務邏輯后,為使數(shù)據(jù)能在internet上傳輸,使用數(shù)據(jù)轉換器把調用結果封裝為SOAP消息。
在客戶端,通過使用JAXM業(yè)務代表,可以降低最終客戶和SOAP消息的耦合度。系統(tǒng)的結構如圖4所示。

當客戶端發(fā)出請求時,它調用JAXMDelegate對應的方法;JAXMDelegate根據(jù)請求構造對應的SOAP消息,然后把消息發(fā)送到服務端;服務端根據(jù)客戶的請求做出對應的處理,并把處理結果返回到JAXMDelegate;JAXMDelegate使用數(shù)據(jù)轉換器把返回的SOAP Message轉化成Java對象(如值Bean),最后返回給客戶端;客戶端再把獲得的數(shù)據(jù)進行處理后顯示。JAXM業(yè)務代表使用數(shù)據(jù)轉換器來轉換數(shù)據(jù),業(yè)務代表直接和Web服務進行交互,屏蔽了Web服務請求的復雜過程,為客戶端提供易于使用的接口。
服務端的模式和客戶端的模式基本一樣,只是處理過程相反。服務端從客戶端接收到SOAP消息后,讀取參數(shù),調用對應的業(yè)務方法,然后使用數(shù)據(jù)轉換器把調用的結果轉換成SOAP消息返回。
4 結束語
JAXM作為輕量級的API,抽象了底層的消息基礎結構。因此,開發(fā)時利用SOAP包裝的JAXM消息是容易的。需要強調的是,如果使用點對點的消息發(fā)送模型,則服務端Servlet必須實現(xiàn)ReqRespListener接口,onMessage( )方法將是開發(fā)服務端Servlet的重點任務。本文通過使用適當?shù)脑O計模式和接口,減少了各層之間的耦合。數(shù)據(jù)轉換在設計中占有很大的分量,業(yè)務代表模式在以上數(shù)據(jù)轉換和業(yè)務處理中起著重要的作用。
參考文獻
1 Sun Microsystems Inc.The Java Web Services Tutorial. http://java.sun.com/webservices/docs/1.0/tutorial/index.html.
2 Kao J.Developer′s Guide to Building XML-based Web Services with the Java 2 Platform,Enterprise Edition (J2EE). http://www.middleware-company.com.
