8.3WEB服務
WEB服務(Web Service)最近年來炙手可熱的技術,本質上說,WEB服務就是一個中能夠實作跨平台遠端的帶哦用的技術标準,即應用程式通過向外界暴露一個可以通過WEB來遠端調用的API接口,用戶端就可以調用這個服務接口來實作相應的功能。
可以把WEB服務堪稱是基于網際網路的遠端調用,有了WEB服務,WEB網站和WEB網站之間就不在是簡單的用超連結連接配接起來,而是可以互相調用的WEB應用程式。
例如,在沒有WEB服務錢,如果需要在women你自己的網站上內建Google搜尋功能,唯一的辦法是通過HTML将使用者導向到Google的站點,而有了WEB服務後,網站可以通過調用Google的WEB服務獲得搜尋結果,然後将結果以任意的方式展示給使用者,對于使用者而言,完全不知道該搜尋結果實際上市重Google得到的。
WEB服務是一種面向服務的架構技術,由于XML是一種平台無關的描述語言,是以,在WEB服務中,XML被用來描述如何傳遞資料。這樣,調用雙方就可以是任意的異構平台,例如,在.Net應用程式中調用Java應用釋出的WEB服務,或者在Java應用程式中調用.Net應用程式釋出的WEB服務。
随着網際網路的迅速發展,WEB服務也得到了越來越廣泛的應用。目前,WEB服務大緻可以應用在以下領域。
(1)面向企業的WEB服務,包括企業内容部各種ERP系統和企業間合作夥伴的系統對接。由于大型企業内部或企業之間常常是異構平台,是以,采用WEB服務來實作系統內建非常合适。
(2)面向消息的WEB服務,尤其是B2C站點,通過WEB服務,第三方桌面應用程式就可以為使用者提供更友善的服務,例如,個人理财軟體可以通過WEB服務獲得最新的股票價格。
(3)面向終端裝置的WEB服務。八塊收集、PDA等各種移動終端,可以通過WEB服務輕松實作天氣預報、酒店預訂等服務。
使用WEB服務帶來的最大的好處是能夠實作跨平台的易購協作,由于WEB服務使用了一系列的标準協定,是以,不同平台、不同語言之間都可以互相調用。一個WEB服務是如何在釋出者和調用者之間實作的如下圖所示:

WEB服務的釋出者首先必須提供一個WSDL檔案,即Web Servcies Description Languange(Web 服務描述語言),這個XML檔案定義了調用Web服務的所有資訊,包括所有的方法名稱,參數類型、傳回類型和資料類型的映射等。WEB服務的調用者隻要獲得了WSDL檔案,就可以根據WSDL檔案通過相應的工具生成用戶端支援類,是以,無論服務段以任何技術實作該WEB服務,用戶端都可以用任何程式設計語言來調用它。
JavaEE平台從1.3 版本開始就完整地支援WEB服務,包括調用和釋出WEB服務兩部分。為了讓Java應用程式獲得通路和釋出WEB服務的能力,Sun定義了一系列相關的API标準,包括SAAJ、JAXB、JAX-RPC和最新的JAX-WS。SAAJ(SOAP with Attachments API for Java)已經完整的實作了SOAP協定,可以直接使用SAAJ實作的WEB服務的底層傳輸。JAXB(JavaArchitecture for XML Binding)則實作了XML資料到Java類的綁定,通常我們不直接使用這兩種API,而是調用高層的JAX-RPC(Java API for XML-Based RPC)和 JAX – WS(Java API for XML-Base Web Servcie)。JAX-WS 是JavaEE最新的WEB服務标準,不過仍向下相容JAX-RPC.
和其他Java标準類似,為了在java中實作WEB服務,還必須獲得一個具體的實作。Axis和Xfire都是實作了完整的WEB服務協定的庫,可以用于通路和釋出WEB服務。稍後我們會分别看到這連個庫的使用方法。
下面我們首先介紹如何使用Axis通路Amaon站點提供的WEB服務,然後介紹如何通過XFire對外釋出我們自己的WEB服務。
8.3.1 通路Amazon的WEB服務
目前略。
8.3.2 在Spring中調用WEB服務
目前略。
8.3.3 釋出WEB服務
前面已經介紹了如何通路已有的WEB服務,women你很自然的向導如果需要釋出自己的WEB服務,應該如何實作。
釋出WEB服務本質上就是最終生成WEB服務的描述檔案,即WSDL檔案,然後告知客戶該檔案的URL。用戶端如果要調用我們釋出的WEB服務,隻需要擷取WSDL檔案,然後從總獲得調用WEB服務所需的全部資訊。WSDL檔案格斯非常複雜,根本不可能手動編寫,更不可能手動維護,因為WSDL檔案設計的目标之一就是能使用工具自動生成讓機器識别的XML。是以要釋出WEB服務,必須借助工具從現有的Java接口及支援自動生成WSDL檔案。
如果讀者使用Microsoft Visual Studio 2005來釋出一個WEB服務,通過幾個簡單的向導頁面,整個釋出過程将不着過一分鐘。遺憾的是,對于JavaEE開發者來說,雖然WEB服務的标準早已被引入到JavaEE體系中,然後,長期以來,在javaEE環境中釋出WEB服務是極其困難的,如果使用Axis釋出一個WEB服務,至少需要手動編寫一個複雜的deploy.wsdd配置檔案,然後需啊喲手動運作AdminClient來生成Axis需要的支援檔案,整個過程比較複雜。
幸運的是,随着新一代的Java WEB服務引擎XFire的釋出,在JavaEE中釋出WEB服務将變得輕而易舉,和其他JavaEE的WEB服務引擎相别,XFire的配置非常簡單,它使得JavaEE開發人員終于可以獲得和.Net開發人員一樣的開發效率,但是在功能上,XFire卻絲毫不遜色于其他的WEB服務引擎,由于使用了StAX(theStreaming API for XML,基于流的XML解析)作為XML解析器,XFire的運作速度優優了質的提高,并且XFire支援最新的JSR181的WEB服務注解。如果使用Java5,隻需要在源代碼中編寫相應的JSR181注解,XFire就可以根據Java5注解自動提取所需要的全部資訊。由于JSR181也是JavaEE WEB服務架構的一部分,使用它最大的好處在于不僅極大的簡化了配置,而且避免了配置檔案和某個特定的WEB服務引擎鎖定(例如,deploy.wsdd是Axis 的配置檔案,在其他WEB服務引擎中不能使用。)
在下面的例子中,我們将看到如何使用XFire釋出WEB服務,并且在Spring環境中內建它。
1. 使用XFire釋出WEB服務
我們首先在單獨的XFire中釋出一個WEB服務,要獲得最新的XFire,請從http://xfire.codehaus.org/ 下載下傳,然後解壓到本地即可。在Eclipse 中建立工程ExportWS工程。
其中,web/WEB-INF/lib目錄下存放了XFire需要的庫檔案,請複制XFire根目錄下的xfire-all-1.2.6.jar及lib目錄下的所有jar檔案。需要注意的是,單獨使用Xfire還需要Spring1.2.x的jar檔案,因為Xfire用到了Spring架構提供的一些功能,不過不用擔心在于Spring2.X架構內建,就不需要Spring1.2.x了,經過測試,XFire與Spring2.0配合的相當好。
有些jar檔案時可選的,可以參考XFire的文檔,删除不必要的Jar檔案,這樣可以減小WEB應用程式的釋出檔案。
以線上書店為例,假定我們的WEB引用程式也準備對外提供了一個書籍查詢的功能,可以根據關鍵字傳回對應的書籍資訊,是以,我們首先編寫一個BookService接口,作為WEB服務的接口。
public interface BookService {
Book[] search(String keyword);
}
然後,編寫一個相應的實作類,這裡,我們的服務幾口還隻能傳回以”j2ee”作為關鍵字書籍的資訊,對于其他的關鍵字,一律傳回一個空數組。
public class BookServiceImpl implements BookService {
@Override
public Book[] search(String keyword) {
if("j2ee".equalsIgnoreCase(keyword)) {
return new Book[] {
new Book("Core J2EE Patterns","Dan Malks"),
new Book("The J2EE Tutorial","Bode Carson"),
new Book("J2EE Design Patterns","William Crawford"),
new Book("J2EE Platform Web Services","Ray Lai")
};
}
return new Book[0];
}
}
下一步,編寫XFire必須的一個WEB服務描述檔案services.xml,該檔案必須放到ClassPaht中的META-INF/xfire/目錄下,在這個工程中,我們将其放到src/META-INF/xfire/目錄下。這個檔案将為XFire提供生成WEB服務的描述資訊,其内容非常簡單,隻需要指定WEB服務的接口和實作類即可。
<beansxmlns="http://xfire.codehaus.org/config/1.0">
<service>
<name>BookService</name> <namespace>http://www.livebookstore.net/BookService</namespace>
<serviceClass>com.zsw.service.BookService</serviceClass>
<implementationClass>com.zsw.service.BookServiceImpl</implementationClass>
</service>
</beans>
最後,在web.xml檔案中加入XFireConfigurableServlet的生命,并映射到指定的路徑。<servlet>
<servlet-name>XFireServlet</servlet-name>
<servlet-class>
org.codehaus.xfire.transport.http.XFireConfigurableServlet
</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/servlet/XFireServlet/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
傳統的處理XML的API有DOM和SAX兩種,DOM速度慢,占用記憶體資源極大,SAX雖然比DOM快,但速度仍不理想,現在,一種新的基于流的Stream API for XML(簡稱StAX)極大的提高了XML的處理速度,并且已經成為JSR173标準,目前,StAX最好的開源實作是Woodstox,它完整的支援StAX API。Resin3.1 也内置了StAxAPI的定義,就會視圖定位一個StAX的實作,為了讓XFire不适用Resin3.1内置的StAX實作,而使用Woodstox的實作,就必須在Resin伺服器啟動的時,指定以下參數。
-Djavax.xml.stream.XMLInputFactory=com.ctc.wstx.stax.WstxInputFactory
-Djavax.xml.stream.XMLOutputFactory=com.ctc.wstx.stax.WstxOutputFactory
-Djavax.xml.stream.XMLEventFactory=com.ctc.wstx.stax.WstxEventFactory
我們需要確定ClassPath包含了StAX API 和Woodtox實作,即/web/lib/目錄下必須有stax-api.jar和wstx-asx-3.0.1.jar.
啟動Resin伺服器,然後打開浏覽器,輸入位址:
http://localhost:8080/services/BookService?wsdl,就可以看到BookServiceWEB服務的WSDL描述文檔,如圖示。
這正是在用戶端調用BookService所需要的唯一資訊,任何需要調用BookService的用戶端隻需要知道這個URL即可調用它。為了測試我們釋出的WEB服務是否能夠正常的在用戶端被調用,下面使用Visual Studio2005 作為用戶端開發環境,直接在C#工程中調用WEB服務。
在Visual Studio2005中建立一個C#Console Application工程,命名為”CallBookService”,然後選擇菜單”Project”- > “Add Web Reference…”,在彈出的對話框框中輸入WSDL的位址并回車,等待幾秒後,VisualStudio 2005就會自動發動發現BookService并找到search()方法,如圖所示:
單擊”添加引用”按鈕後,BookService就被自動添加進了工程中,Visual Studio2005會自動為該WEB服務生成用戶端支援檔案/WebReferences/localhost/Reference.cs,其命名空間為CallBookService.localhost,如圖:
打開Program.cs檔案,編寫代碼調用BookService,如圖namespace
{
class Program
{
static void Main(string[] args)
{
Book[] books = new BookService().search("j2ee");
foreach (Book bookin
{
Console.WriteLine("書的作者:{0}, 書的名稱:{1}",book.author,book.name);
}
}
}
}
運作C#代碼,在控制台視窗可以看到如下輸出:
書的作者:Dan Malks, 書的名稱:Core J2EE Patterns
書的作者:Bode Carson, 書的名稱:The J2EE Tutorial
書的作者:William Crawford, 書的名稱:J2EE Design Patterns
書的作者:Ray Lai, 書的名稱:J2EE Platform Web Services
請按任意鍵繼續. . .
調用成功!說明我們釋出的WEB服務确實能夠被異構平台正确調用。也可以使用其他任何支援WEB服務的語言來調用該WEB服務u,包括前面介紹的在Spring中通路WEB服務的方法。
2. 在Spring中內建XFire
在前面我們看到了XFire作為WEB服務引擎能極大的簡化WEB服務的釋出。由于WEB服務不過是為了将系統内部的某些功能暴露給外部,是其他的易購用戶端能夠調用系統那個的某些功能,是以,僅僅編寫了一個簡單的JavaBean作為WEB服務端實作是不符合實際應用的,一個實際應用程式的WEB服務必然要設計調用系統内部的邏輯元件,包括通路資料庫以擷取必要的資料等。我們知道如何在Spring的IOC容器中完成所有元件的部署,如果希望将某些元件的功能暴露為WEB服務,就必須以某種方式将XFire內建到Spring應用程式中。
幸運的是,XFire提供了對Spring的完善支援,并且在Spring2.0環境下沒有任何問題。下面的例子将描述如何在Spring2.x架構中內建XFire并釋出WEB服務。
我們将ExportWS工程複制一份,重新命名為ExportWS_Spring,然後将web/WEB-INF/lib目錄下的Spring-1.2.x.jar替換為Spring2.0的jar檔案,此外,src/META-INF/xfire/services.xml也不需要了,直接将整個META-INF目錄删掉,WEB服務的相關資訊稍後将直接在Spring的XML配置檔案dispatcher-servlet.xml中定義。
在上一個例子中,我們仍使用了傳統的XML配置檔案來聲明WEB服務,現在,我們使用JSR181WEB服務注解來直接标注WEB服務。對BookServieImpl增加了如下注解。
|
JSR181 的注解非常簡單,讀者可以很容的猜出各個注解的含義。
和普通的Spring WEB應用程式一樣,在web.xml檔案中聲明Spring的DispatcherServlet。
|
然後編寫Spring的XML配置檔案dispatcher-servlet.xml,内容如下:
|
需要注意的是,這個XML配置檔案必須首先通過<import>引入XFire的一些預定義的Bean,這樣就可以直接使用XFireExporter來處理WEB服務請求。這個配置詳單簡單。由于是在Spring的容器中配置的,對于bookService來說,隻要注入了通路資料庫的元件(例如,BookDao),就以整整實作一個有用的WEB服務。
讀者仍可以使用Microsoft Visual Studio 2005來測試這個通過Spring內建的XFire釋出的WEB服務,不過請注意,這個工程的BookService WEB服務的URL位址變為http://localhost:8080/BookService?wsdl。
現在,我們已經詳細介紹了WEB服務的原理,如何調用和釋出WEB服務,以及如何在Spring架構中內建Web服務。在調用WEB服務時,我們使用的是Axis,但用戶端代碼使用的是标準的JAX-RPC接口,是以,不存在綁定Axis的問題。如果系統使用XFire來調用WEB服務,可以使用XFire提供的wsdl2java工具來生成相應的支援類,用戶端代碼是不變的。在釋出WEB服務時,我們隻介紹如何使用XFire來實作,因為相比其他的Web服務引擎,XFire在實作WEB服務上有巨大的配置和性能優勢,是以XFire應當作為JavaEE環境下釋出WEB服務的首選。
Spring 架構的另一個子項目Spring WEB Services(http://www.springframework.org/spring-ws)的目标就是一個提供了一個與Spring緊密結合的WEB服務子產品,并與Spring的MVC架構內建,這個項目可以作為Spring架構下釋出WEB服務的一個選擇。
在Java6中有一個重大的特性就是對WEB服務的内在支援,釋出和通路WEB服務都變得輕而易舉。如果采用基于Java6的WEB服務,那麼不必使用任何第三方WEB服務的支援庫,就可以直接将WEB服務完美的內建進來。
8.4 小結
在這裡主要介紹了JavaEE平台的各種遠端的調用技術,以及如何在Spring架構中友善的內建他們,即包括了作為用戶端帶哦用遠端服務,也包括了如何在Spring環境中釋出遠端服務。下面,我們來比較以下各種遠端調用的特點和适用範圍。
(1)RMI:RMI協定是專門為Java設計的一種二進制協定,這意味着RMI隻能在Java應用程式間通信,而無法與非Java應用程式通信。此外,RMI使用專用的端口,這使得RMI很難穿透防火牆。RMI的好處在于可以直接傳輸Java對象,是以實作起來非常的簡單。
(2)Hessian、Burlap和Spring HTTP Invoker:這3中協定都是基于HTTP的輕量級協定,是以,很容易穿透防火牆,并且理論上采用XML格式的Burlap可以和其他任意應用程式通信,隻要對方能正确解析XML。但是。由于這3中協定都是私有協定,沒有成為标準,實際應用較少,是以不土建使用這3中協定來實作遠端調用。
(3)Web Service : Web服務早已經成為工業标準,被所有的大廠商支援,并且在網際網路上得到廣泛的應用。由于以HTTP為基礎,是以可以很容易穿透防火牆,并且由于XML的平台無關性,通信雙方可以而使用任何平台。Web Service的缺點在于部署和調用都相對困難,而且效率較低。