JAXM開(kāi)發(fā)Web服務(wù)的構(gòu)架和模式(good2)
級(jí)別: 初級(jí)
陳亞強(qiáng), 高級(jí)軟件工程師
2003 年 6 月 01 日
本文是本系列的第二篇,前一篇我們介紹了JAXM的開(kāi)發(fā)技術(shù),在這篇里,我將結(jié)合前一篇的案例來(lái)討論JAXM Web服務(wù)的構(gòu)架和設(shè)計(jì)模式。
本文是本系列的第二篇, 前一篇我們介紹了JAXM的開(kāi)發(fā)技術(shù),在這篇里,我將結(jié)合前一篇的案例來(lái)討論JAXM Web服務(wù)的構(gòu)架和設(shè)計(jì)模式。
閱讀本文前您需要以下的知識(shí)和工具:
JavaTM Web Services Developer Pack 1.1,并且會(huì)使用初步使用;
至少會(huì)使用一種EJB容器來(lái)開(kāi)發(fā)、部署EJB,并且會(huì)在客戶端調(diào)用EJB組件;
對(duì)J2EE平臺(tái)有比較全面的了解;
對(duì)UML比較熟悉。
本文的參考資料見(jiàn) 參考資料
本文的全部代碼在這里 下載
![]() |
|
JAXM使用SOAP消息在消息客戶端和服務(wù)端傳送消息,消息有兩種類(lèi)型,一種是SOAPConnection,另一種是ProviderConnection。前者是一種點(diǎn)對(duì)點(diǎn)的消息發(fā)送模型,后者需要通過(guò)MessageProvider來(lái)把消息傳送到目標(biāo)。它們的消息傳送路徑如圖1所示。

圖1 單向和雙向的消息傳送方式
不使用MessageProvider,可以帶來(lái)一些便利,比如:
客戶端可以是一般的J2SE程序(本文講述的案例就是如此);
不需要額外的配置。
但是,不使用MessageProvider也有以下的限制:
只能發(fā)送request-response類(lèi)型的消息;
客戶端只能是客戶端的角色。
本文的案例采用了點(diǎn)對(duì)點(diǎn)的消息傳送方式,調(diào)用環(huán)境如圖2所示。

圖2 JAXM調(diào)用環(huán)境
![]() |
|
系統(tǒng)體系結(jié)構(gòu)如圖3所示。

圖3 系統(tǒng)體系結(jié)構(gòu)
上圖的分層模型和J2EE應(yīng)用程序的分層模型基本一致,不同的是客戶端和JAXM Servlet數(shù)據(jù)的通信是封裝成SOAP,但是,它也是HTTP的調(diào)用。
![]() |
|
本案例共有三個(gè)用例,它們分別是按名字查找書(shū),按類(lèi)別查找書(shū),查找所有的書(shū)。如圖4所示。

圖4 用例圖
![]() |
|
在數(shù)據(jù)庫(kù)里,圖書(shū)信息用圖5的格式保存。

圖5 數(shù)據(jù)庫(kù)表
為了傳輸數(shù)據(jù)的方便,減少遠(yuǎn)程調(diào)用的次數(shù),特別設(shè)計(jì)了BookVO來(lái)代表圖書(shū)的信息,BookVO是一個(gè)值對(duì)象,如圖6所示。

圖6 BookVO值對(duì)象類(lèi)圖
值對(duì)象設(shè)計(jì)模式在J2EE模式中是非常有名且大量使用的設(shè)計(jì)模式,相信讀者會(huì)很熟悉。我們知道,JAXM Servlet和EJB組件之間傳遞數(shù)據(jù)是通過(guò)對(duì)象來(lái)傳遞的,這個(gè)對(duì)象就是包含有BookVO實(shí)例的java.util.Collection。但是JAXM和客戶端是通過(guò)SOAP消息來(lái)傳遞的(當(dāng)然,也可以使用序列化的對(duì)象作為附件發(fā)送),為了傳輸圖書(shū)信息,我們就要定義對(duì)應(yīng)的DTD(或者schema)。針對(duì)以上的模型,定義的DTD如例程1所示。
例程1 傳輸圖書(shū)信息的格式(book.dtd)
|
![]() |
|
業(yè)務(wù)層是EJB組件,這里使用了兩個(gè)EJB組件,一個(gè)是BookServiceFacadeEJB,它是一個(gè)有狀態(tài)會(huì)話Bean,另一個(gè)是BookEntityEJB,它是一個(gè)實(shí)體Bean,代表了BookEntityTable的持久數(shù)據(jù)。
BookEntityEJB組件類(lèi)圖如圖7所示。

圖7 BookEntityEJB組件的類(lèi)圖
其中,isbn是BookEntityEJB組件的主鍵,BookEntityHome定義了幾個(gè)find方法,它們是:
findAllBook(),查找所有的書(shū),返回的是由BookEntity組成的Collection;
findByCategory(String category),按類(lèi)別查找書(shū),返回的是由BookEntity組成的Collection;
findByName(String name),按書(shū)名查找書(shū),返回的是一個(gè)BookEntity的遠(yuǎn)程引用。
BookServiceFacadeEJB是會(huì)話門(mén)面,JAXM Servlet通過(guò)它來(lái)和BookEntityEJB交互。它的類(lèi)圖如下:

圖8 BookServiceFacadeEJB組件的類(lèi)圖
同樣,它也定義了幾個(gè)find方法,但是和BookEntityHome接口不同的是,它返回的是包含了BookVO值對(duì)象的Collection,而不是包含了BookEntity遠(yuǎn)程引用的Collection。具體的實(shí)現(xiàn)細(xì)節(jié)請(qǐng)參考源代碼。
EJB組件之間的依賴(lài)關(guān)系如圖9所示。

圖9 EJB組件之間的依賴(lài)關(guān)系
![]() |
|
在JAXM 服務(wù)端設(shè)計(jì)了三個(gè)服務(wù)JAXM Servlet,分別對(duì)應(yīng)了圖4中的三個(gè)用例,它們是:
ListAllBook:查找所有的書(shū);
BookDetail:按書(shū)名查找某本特定的圖書(shū);
ListByCategory:按類(lèi)別查找。
它們的建模關(guān)系如圖9所示。

圖9 服務(wù)端JAXM Servlet的類(lèi)圖
每個(gè)JAXM Servlet都有一個(gè)SOAPMessage onMessage(SOAPMessage message)方法,這個(gè)方法在它們接收到SOAP消息時(shí)調(diào)用,可以說(shuō)是客戶端調(diào)用服務(wù)端的入口。
![]() |
|
最終客戶端是一個(gè)叫BookClientGUI的圖形界面程序,它并不直接和SOAP消息打交道,它是通過(guò)JAXMDelegate類(lèi)來(lái)和服務(wù)端JAXM Servlet進(jìn)行交互的,這里我們簡(jiǎn)單列出它的類(lèi)圖,在接下來(lái)的設(shè)計(jì)模式里將詳細(xì)介紹。

圖10 客戶端類(lèi)圖
在上圖中,請(qǐng)注意到BookBusiness接口,它是BookClientGUI和JAXMDelegate通信的橋梁,這里也體現(xiàn)了面向接口編程的思想。
![]() |
|
JAXM進(jìn)行Web服務(wù)開(kāi)發(fā)還不是特別普遍,故對(duì)它的設(shè)計(jì)模式的探討還比較少。但是它也有它自己的特點(diǎn),基本上來(lái)說(shuō),它的設(shè)計(jì)模式和J2EE平臺(tái)其它組件設(shè)計(jì)模式是一致的。我們?cè)谑褂肑2EE設(shè)計(jì)模式時(shí),基本上有以下幾點(diǎn)的考慮:
- 減少遠(yuǎn)程調(diào)用的次數(shù)(使用值對(duì)象、值列表組裝器、值對(duì)象組裝器模式)
- 降低組件之間、層(Tier)之間的耦合(使用會(huì)話門(mén)面、業(yè)務(wù)代表模式)
- 減少服務(wù)查找的復(fù)雜度(使用服務(wù)定位器模式)
- 數(shù)據(jù)的一致訪問(wèn)(使用數(shù)據(jù)訪問(wèn)對(duì)象模式)
- 進(jìn)行異步通信(使用服務(wù)激發(fā)器模式)
JAXM也是J2EE平臺(tái)的一種技術(shù),它當(dāng)然可以使用J2EE核心模式中的任何一種,但是它有自己的特點(diǎn),比如客戶端和服務(wù)端是通過(guò)SOAP消息進(jìn)行通信,這個(gè)和J2EE平臺(tái)的其它組件之間通信是不同的。在JAXM編程中,為了實(shí)現(xiàn)數(shù)據(jù)(這里是SOAP消息)的一致返回,我們可以使用XML業(yè)務(wù)代表的模式。
JAXM進(jìn)行編程時(shí),數(shù)據(jù)傳遞的特點(diǎn)如圖11所示。

圖11 JAXM數(shù)據(jù)傳輸?shù)奶攸c(diǎn)
從上圖可以看出,客戶端最終要使用的數(shù)據(jù)是java對(duì)象或者Java的基本數(shù)據(jù)類(lèi)型,而客戶端和服務(wù)端的通信是通過(guò)SOAP消息格式來(lái)傳輸?shù)模煌瑯樱诜?wù)端,它要調(diào)用業(yè)務(wù)邏輯,也必須使用java對(duì)象或者是java基本數(shù)據(jù)類(lèi)型。這樣就存在數(shù)據(jù)的傳輸和數(shù)據(jù)的使用的矛盾,為了解決這個(gè)矛盾,降低層(Tier)之間的耦合度,使數(shù)據(jù)易于處理,我們可以使用一個(gè)數(shù)據(jù)轉(zhuǎn)換器來(lái)轉(zhuǎn)換數(shù)據(jù)。當(dāng)客戶端要發(fā)送數(shù)據(jù)時(shí),它使用數(shù)據(jù)轉(zhuǎn)換器把請(qǐng)求數(shù)據(jù)轉(zhuǎn)換成SOAP消息格式;在服務(wù)端,它調(diào)用了業(yè)務(wù)邏輯后,為了使數(shù)據(jù)能在internet上傳輸,它要使用數(shù)據(jù)轉(zhuǎn)換器把調(diào)用結(jié)果封裝成SOAP消息。接下來(lái)我們來(lái)看怎么處理這個(gè)問(wèn)題。
![]() |
|
在客戶端,通過(guò)使用JAXM業(yè)務(wù)代表,可以降低最終客戶和SOAP消息的耦合度。系統(tǒng)的結(jié)構(gòu)如下。

圖12 JAXM業(yè)務(wù)代表
JAXM業(yè)務(wù)代表使用數(shù)據(jù)轉(zhuǎn)換器來(lái)轉(zhuǎn)換數(shù)據(jù),業(yè)務(wù)代表直接和Web服務(wù)進(jìn)行交互,它屏蔽了Web服務(wù)請(qǐng)求的復(fù)雜過(guò)程,為客戶端提供易于使用的接口。
此案例中,具體實(shí)現(xiàn)的類(lèi)圖如下:

圖13 客戶端類(lèi)圖
圖中的JAXMDelegate為JAXM業(yè)務(wù)代表,它實(shí)現(xiàn)了BookBusiness接口,它是此模式的核心,它實(shí)現(xiàn)的方法是客戶端可以直接調(diào)用的方法。
BookBusiness接口定義了和最終客戶端(BookClientGUI)交互的方法,BookBusiness接口如例程2所示。
例程2 BookBusiness接口
|
SOAPToBeanEngine是數(shù)據(jù)轉(zhuǎn)換器,它負(fù)責(zé)把具體的SOAP消息轉(zhuǎn)換成客戶端可以使用的數(shù)據(jù)。SOAPToBeanEngine實(shí)現(xiàn)了DTOEngine接口,我們看DTOEngine接口的具體代碼,如例程3所示。
例程3 DTOEngine接口
|
以上三個(gè)方法是每個(gè)把SOAP消息轉(zhuǎn)換成Java對(duì)象的數(shù)據(jù)轉(zhuǎn)換器(如SOAPToBeanEngine)都必須實(shí)現(xiàn)的方法。實(shí)際上,這里的SOAPToBeanEngine只能轉(zhuǎn)換BookVO相關(guān)的信息,如果要把此模式的框架設(shè)計(jì)得更加完美,還需進(jìn)一步抽象,比如抽象到只要傳入相關(guān)的值對(duì)象類(lèi)(BookVO.class)和SOAP Message就能轉(zhuǎn)換成對(duì)應(yīng)的Bean結(jié)果集。
當(dāng)客戶端(BookClientGUI)發(fā)出一請(qǐng)求時(shí),它調(diào)用JAXMDelegate對(duì)應(yīng)的方法,JAXMDelegate根據(jù)請(qǐng)求構(gòu)造對(duì)應(yīng)的SOAP消息,然后把消息發(fā)送到服務(wù)端(如ListByCategory Servlet),服務(wù)端根據(jù)客戶的請(qǐng)求做出對(duì)應(yīng)的處理,并把處理結(jié)果返回到JAXMDelegate,JAXMDelegate使用SOAPToBeanEngine把返回的SOAP Message轉(zhuǎn)化成Java對(duì)象(如值Bean),最后返回給客戶端(BookClientGUI),BookClientGUI再把獲得的數(shù)據(jù)進(jìn)行處理后顯示。
假如客戶端要按類(lèi)別查詢圖書(shū)信息,我們來(lái)看下一個(gè)順序圖,如圖14所示。

圖14 按類(lèi)別查詢圖書(shū)客戶端順序圖
JAXMDelegate是此模式的核心,我們來(lái)看一下它的代碼,如例程4所示。
例程4 JAXMDelegate的部分代碼
|
![]() |
|
服務(wù)端的模式和客戶端的模式基本一樣,只是處理過(guò)程相反。服務(wù)端從客戶端接收到SOAP消息后,然后讀取參數(shù),調(diào)用對(duì)應(yīng)的業(yè)務(wù)方法,然后使用SOAPToBeanEngine來(lái)把調(diào)用的結(jié)果轉(zhuǎn)換成SOAP消息返回。
如圖15所示是相應(yīng)的數(shù)據(jù)轉(zhuǎn)換模型。

圖15所示是相應(yīng)的數(shù)據(jù)轉(zhuǎn)換模型
在服務(wù)端,數(shù)據(jù)轉(zhuǎn)換器負(fù)責(zé)把對(duì)象轉(zhuǎn)換成SOAP消息,這里和客戶端是相反的。服務(wù)端類(lèi)圖如下。

圖16 服務(wù)端類(lèi)圖
在圖16中,OTDEngine接口定義了把Bean轉(zhuǎn)換成SOAP消息的方法,如例程5所示。
例程5 OTDEngine接口定義的方法
|
OTDEngine定義了把Bean轉(zhuǎn)換成SOAP消息需要的方法:build()、init()、getResult()。
XMLBusinessDelegate是此模式的核心,它調(diào)用業(yè)務(wù)邏輯,并且使用BeanToSOAPEngine來(lái)轉(zhuǎn)換結(jié)果。我們來(lái)看它的部分代碼,如例程6所示。
例程6 XMLBusinessDelegate部分代碼
|
假如客戶端傳來(lái)要按類(lèi)別查詢圖書(shū)信息,ListByCategory Servlet將調(diào)用XMLBusinessDelegate 的listByCategory(String category)方法,XMLBusinessDelegate查找BookServiceFacadeHome接口,生成BookServiceFacade應(yīng)用,調(diào)用getBookDetail(name);方法,然后初始化OTDEngine,最后調(diào)用getResult()方法來(lái)返回結(jié)果。順序圖如圖17所示。

圖17 按類(lèi)別查找圖書(shū)的服務(wù)端順序圖
![]() |
|
本篇結(jié)合具體的案例介紹了JAXM Web服務(wù)開(kāi)發(fā)的體系結(jié)構(gòu)和設(shè)計(jì)模式。數(shù)據(jù)轉(zhuǎn)換在設(shè)計(jì)中占有很大的分量,總的來(lái)說(shuō),從客戶端發(fā)出的數(shù)據(jù)要經(jīng)過(guò)以下途徑:
java數(shù)據(jù)類(lèi)型àSOAP請(qǐng)求消息àjava數(shù)據(jù)類(lèi)型à業(yè)務(wù)邏輯返回的java數(shù)據(jù)類(lèi)型àSOAP相應(yīng)消息àjava數(shù)據(jù)類(lèi)型
業(yè)務(wù)代表模型在以上數(shù)據(jù)轉(zhuǎn)換和業(yè)務(wù)處理起著重要的作用。
posted on 2005-12-16 16:56 Victor 閱讀(454) 評(píng)論(0) 編輯 收藏 所屬分類(lèi): web services