天天看點

web services[for xfire]

Web Services使我們能夠在網絡上建立分布式系統,應用程式元件可以通過任何平台、任何語言和任何方式通路。無論應用程式如何開發,使用了什麼語言,以 及運作在什麼作業系統平台上,隻要它作為Web Service,并且為協同解決問題而設計,那麼你的應用程式,以任何語言開發或在任何平台上,都可以利用它的服務。這是Web Service的主要概念。

  為了實作Web Services的平台無關性和實作通路獨立性,軟體行業需要遵循一些作為标準的技術。其中一些包括:

  ---XML:在Web Services環境中各層之間進行傳遞的預設資料格式。

  ---SOAP:封裝和交換資訊的預設協定。第一次被提出時,它是隻取Simple Object Access Protocol(簡單對象通路協定)的首字母。但是現在SOAP更多被認為是一個特定的名詞,以它自己而命名,同樣很多人認為這是用詞不當:SOAP實 際上不是用來通路對象的。另外,它也不再簡單。

  ---WSDL(Web Services Description Language,Web Services描述語言):描述Web Services的語言。盡管基于XML并且可以被人了解,WSDL主要是由機器處理,由用戶端程式讀取和了解。

  下面的進階層次圖表,基于WWW協會釋出的“Web Services Architecture”(Web Services架構)文檔,顯示了這些技術在實際的工作環境中是如何發揮作用:

  這個流程圖顯示了Web Services中的核心技術是如何工作的。

  這裡,Provider是提供服務的應用程式元件,Requester是使用服務的用戶端程式。很多其他技術也會參與到互動中,但是這個圖隻顯 示了在Web Services環境中必需的核心技術元件。

  XFire是一個免費的開源SOAP架構,它不僅可以極大友善地實作這樣一個環境,并且可以提供許多Web Services規範中進階特征,這些特征在多數的商業或者開源工具都沒有提供。你要恰當的了解這些單詞:great ease and simplicity(非常輕松和簡單)。你将會看到使用XFire建立Web Services是多麼的簡單。

  假如你的Web應用有一個Java類,并且你想把它的一個方法釋出為Web Services,當使用XFire時,你不需要編寫一行額外的Java代碼。隻需要編輯釋出描述符,然後你就會得到一個Web Services。是的,它相當地簡單。我們來看一個例子。

  一個簡單的Java類

  我們的例子是一個銀行業應用程式,伺服器是運作在J2SE1.4.2_07下的Apache Tomcat5.5.7。假定你已經了解如何使用Java編寫Web應用程式,并知道應該如何把它部署到Apache Tomcat伺服器上。我們的Web應用程式非常簡單;它隻做一件事——将資金從一個賬戶轉到另外一個賬戶上。一個普通的Java類 BankingService包含了一個叫做transferFunds()的方法來為我們完成這項工作。它需要四個輸入參數:

•   1、 String fromAccount

•   2、 String toAccount

•   3、 double amount

•   4、 String currency

  代碼如下:

package com.mybank.xfire.example;
import java.text.NumberFormat;
import java.text.DecimalFormat;
/** XFire WebServices sample implementation class. 
*/
public class BankingService implements IBankingService {

    //Default constructor.
    public BankingService(){    
    }

    /** Transfers fund from one account to another.
    */
    public String transferFunds(
        String fromAccount, String toAccount, double amount, String currency){

        String statusMessage = "";

        //Call business objects and other components to get the job done.
        //Then create a status message and return.
        try {
            NumberFormat formatter = new DecimalFormat("###,###,###,###.00");       
            statusMessage = "COMPLETED: " + currency + " " + formatter.format(amount)+ 
            " was successfully transferred from A/C# " + fromAccount + " to A/C# " + toAccount;
        } catch (Exception e){
            statusMessage = "BankingService.transferFunds(): EXCEPTION: " + e.toString();
        }
        return statusMessage;
    }

}
           

  在這裡你看到了什麼異常的東西了嗎?或許沒有,除了預設的構造函數,類型是public。這是必須的。否 則,XFire不能夠初始化這個類。

  因為使用接口的設計是一個好的實踐,是以我們的Java類也實作了一個稱為

IBankingService的接口。代碼十分簡單:
package com.mybank.xfire.example;
public interface IBankingService {  
    public String transferFunds(
        String fromAccount, String toAccount, double amount, String currency);

}
           

  在實際實作中,這樣一個方法可能包括各種類型的複雜調用、查詢和處理操作。但是我們的示例代碼已經最小化了,以至于我們可以集中精力在主要目标 上:把這個方法釋出為Web Services。

  你可以看到BankingService是一個普通的Java類,沒有任何代碼告訴我們它将會在Web Services中使用。好的,這裡我們不需要增加任何東西。我們所有的工作都在部署描述符裡完成。

  Web應用的部署描述符

  在Java中,Web應用程式通常需要至少一個部署描述符(叫做web.xml)對其進行配置。XFire本身是一個基于servlet的應用 程式。是以,我們需要增加必要的引用到描述符檔案中。然後我們還必須配置将要建立的Web Services。我們使用一個稱為services.xml的新檔案來完成這件事。

  web.xml

  首先,修改web.xml。我們需要增加下面的XFire servlet相關的條目:

<servlet>

<servlet-name>XFireServlet</servlet-name>

<display-name>XFire Servlet</display-name>

<servlet-class>org.codehaus.xfire.transport.http.XfireConfigurableServlet

</servlet-class>

</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>

  services.xml

  現在我們不得不說一下我們的Web Services的由什麼組成的了。這由一個叫做services.xml的檔案完成,它存放在META-INF/xfire目錄下,而這整個目錄放在 WEB-INF/classes檔案夾中,它在Web應用程式的标準類路徑中。這裡是services.xml中的基本配置條目:

<beans xmlns="http://xfire.codehaus.org/config/1.0">

<service>

<name>Banking</name>

<namespace>mybank</namespace>

<serviceClass>com.mybank.xfire.example.IBankingService</serviceClass>

<implementationClass>com.mybank.xfire.example.BankingService</implementationClass>

</service>

</beans>

  讓我們看看這裡都包含了什麼内容。Web Services的定義包含在元素中,它還含有一 些子元素。第一個子元素是,它可以是你提供任何的合法名字。這将會被用戶端程式和其它需要定位你的服務的元件用到。例如,在服務準備好以後, 你将在浏覽器上使用這個名字來檢視WSDL。

  下一個子元素是<namespace>。任何合法的 XML名字都是可以的。<namespace>用來唯一辨別你的服務的各個參數。

<serviceClass>元素包含 了Java類的名字,它指定了方法簽名。在我們的例子中,它是接口IBankingService。如果Java類沒有實作任何接口,你就需要把類的名字 放在這裡。在你的Java類或者接口中可能有幾個方法。隻需要一個入口把它們全部釋出為Web Services。

  <implementationClass>儲存了實作 方法的Java類名。這是一個可選元素。如果上一個元素<serviceClass>包含了一個接口,那麼相應的實作類必須在這裡指定。

  就是這樣。我們的Web Services配置完成了。

  XFire和其它類庫

  現在是最後一步了,需要得到所有必需的類庫。我們怎樣得到它們呢?去XFire網站,下載下傳xfire- distribution-1.0.zip,然後解壓到一個本地檔案夾。複制下面的jar檔案和它的庫檔案夾到WEB-INF/lib中:

•   • activation-1.0.2.jar

•   • commons-codec-1.3.jar

•   • commons-httpclient-3.0.jar

•   • commons-logging-1.0.4.jar

•   • jaxen-1.1-beta-8.jar

•   • jdom-1.0.jar

•   • log4j-1.2.x.jar

•   • mail-1.3.3_01.jar

•   • spring-1.2.x.jar

•   • stax-api-1.0.jar

•   • wsdl4j-1.5.2.jar

•   • wstx-asl-2.9.jar

•   • xbean-2.1.0.jar

•   • xbean-spring-2.2.jar

•   • xfire-all-1.0.jar

•   • XmlSchema-1.0.jar

  一切妥當。我們來部署和啟動應用程式。為了部署示例應用,隻需要複制websvc.war到Apache Tomcat的webapps檔案夾中,再等待幾秒鐘。它将會自動啟動。這個應用的全部源代碼也包含在這個war檔案中。我們的程式已經準備作為一個 Web Service了。

  我們如何知道Web Service正在工作呢?

  為了了解Web Service是否正在工作,我們需要測試。首先,我們測試來看WSDL是否可用。我們在浏覽器中輸入URL。哪個URL?因為我們的應用程式的war文 件是websvc.war,并且在services.xml中給出的服務名是Banking,WSDL的URL應該 是:http://localhost:8080/websvc/services/Banking?wsdl。

  請注意:URL的第一部分,例如,http://localhost:8080,可能會根據你的應用伺服器不同而不同。無論怎樣,當你輸入 URL後,将會看到一個XML文檔,它的根元素是。這個文檔叫做服務的WSDL。如果你看到了,這就是你的應用作為 Web Service已經可用的第一個證明。

  但是這個測試是不夠的。可能會發生這種情況,可以看到WSDL,但是從用戶端程式可能會通路不到服務。是以為了核實服務是否可以通路了,我們必 須使用一個用戶端進行服務的實際調用來進行一個真正的測試。

  開發一個用戶端

  你可以使用任何的SOAP工具建立用戶端,例如,.Net或者Apache Axis,有很多種方法:使用從WSDL産生的stubs,使用動态代理,等等。在例子中,我們使用一個動态代理,以一個簡單的Servlet形式,叫做 WsClient.java。為了保持代碼兩最小,所有在螢幕顯示的元素都放在了doGet()方法中。對Web Service的實際調用由callWebService()方法完成,它相當地簡單。和下面的類似:

/* Call the Web service
    *
    */
    public String callWebService(
        String fromAccount, String toAccount, double amount, String currency) 
        throws MalformedURLException, Exception {

        //Create a metadata of the service      
        Service serviceModel = new ObjectServiceFactory().create(IBankingService.class);        
        log.debug("callSoapServiceLocal(): got service model." );

        //Create a proxy for the deployed service
        XFire xfire = XFireFactory.newInstance().getXFire();
        XFireProxyFactory factory = new XFireProxyFactory(xfire);      

        String serviceUrl = "http://localhost:8080/websvc/services/Banking";

        IBankingService client = null;
        try {
            client = (IBankingService) factory.create(serviceModel, serviceUrl);
        } catch (MalformedURLException e) {
            log.error("WsClient.callWebService(): EXCEPTION: " + e.toString());
        }    

        //Invoke the service
        String serviceResponse = "";
        try { 
            serviceResponse = client.transferFunds(fromAccount, toAccount, amount, currency);
       } catch (Exception e){
            log.error("WsClient.callWebService(): EXCEPTION: " + e.toString());                 
            serviceResponse = e.toString();
        }        
        log.debug("WsClient.callWebService(): status=" + serviceResponse);              
        //Return the response
        return serviceResponse;
    } 
           

  這個代碼是如何工作的呢?我來解釋一下:首先,我們建立一個服務模型,它包含服務的說明——換句話說,就是服務的中繼資料。我們使用XFire的 ObjectServiceFactory從IBankingService.class接口建立這個模型。

  接着,為XFire獲得一個代理工廠對象,它包含了正常的代碼,也相當地簡單和易懂。這一步中沒有任何特定應用的東西。從這個 proxyFactory,使用服務模型和服務端點URL(用來獲得WSDL),我們可以得到一個服務的本地代理。

  就是它了。這個代理就是實際的用戶端。現在,我們可以調用它的transferFunds()方法來得到我們需要 的Web Service。

  一旦示例應用釋出并啟動,就可以嘗試servlet URL:

  http://localhost:8080/websvc/ws。

  這個Servlet使用預設參數來調用Web Service和顯示接收到的響應。頁面的最後兩行應該讀取:

  Response Received

  COMPLETED: CDN$ 500.00 was successfully transferred from A/C# 11111-01234 to A/C# 99999-05678

  現在你可以确定Web Service已經釋出并且在運作中了。

  為了嘗試不同的輸入值,你可以使用完整的URL,例如:

  http://localhost:8080/websvc/ws?from=11-2345& to=77-9876&amt=250.00&cur=EUR。

  基本的Web Services開發步驟清單

  這個清單總結了将一個Java方法釋出為Web Service所必須的步驟:

•   1、 檢查Java類的方法和預設構造函數確定為public

•   2、 增加XFire servlet相關條目到web.xml中

•   3、 建立services.xml,把它放到WEB-INF/classes/META-INF/xfire目錄下

•   4、 增加XFire和第三方包到你的Web應用的WEB-INF/lib檔案夾中

  這就是所有需要的步驟,是的,相當簡單。

  XFire的其他進階特性

  XFire的使用可能比較簡單,但是在特性和功能性上,它卻占據着上司者的位置。下面是它的進階特性:

•   ---本地資料綁定支援POJOs(plain-old Java objects)、XMLBeans、JAXB(Java Architecture for XML Binding)、Castor等等。資料綁定說明了Web Services的XML請求和映射到Java對象的XML響應。

•   ---使用StAX(Streaming API for XML)處理XML文檔。同DOM的基于樹和SAX的事件驅動的處理方式相比,StAX使用了拉(pull)機制,它使處理更快速,記憶體效率更高。

•   ---支援多種傳輸協定,如HTTP、JMS(Java Message Service)和JVM内部傳輸。

•   ---嵌入式,這是XFire的核心功能之一。你可以把這個SOAP引擎嵌入到你的 應用中,完全隐藏所有XFire特定引用,同樣所有配置都是程式驅動。

•   ---豐富的API,它使XFire可高度自定義,允許開發者在不同的階段截獲請 求,并且對他們進行處理。

•   ---相容最新的标準例如SOAP1.1(沒有加密遠端工程調用,或者RPC)和 1.2、WSDL1.1、the Web Services Interoperability Organization’s Basic Profile 1.0、Web Services Addressing和WS-Security。

  最重要的是,XFire屬于新一代Web Services引擎。不僅僅是營銷用語,“新一代”有一些重要的意義。Apache Axis是第一代Java語言的Web Services引擎,已經成為了所有後來工具的參考标準。在過去的幾年裡,Axis以及這些其它的工具已經在很多生産環境中進行了實地測試。從中得出的 一個關鍵的問題就是Web Services并不最适合RPC類型的通信。對于性能和效率,面向文檔的消息形式是最好的方式。但是Apache Axis和很多其他的Web Services引擎都被設計成了面向RPC的(盡管它們支援文檔形式)。現在,整個行業正在開發新一代的SOAP引擎,設計為面向文檔的。Apache 已經宣布結束舊版本的Axis引擎開發,現在專注于Axis2,現在它的預釋出版本是0.95。XFire在今年的2月份釋出了它的第一個産品版本 (1.0)。它的下一個版本(1.1)僅僅在幾個星期之後就進行了釋出。

  性能

  Web Services需要消耗很多資源,但是性能方面它們不是那麼引人注目。XFire打破了這種趨勢。它消耗更少的記憶體(部分因為 StAX的使用),但是表現卻比多數可比較的SOAP引擎出色。你可以在資源中提供的連結中看到比較的結果。

  此外,XFire還提供了各種方法來進一步優化性能。一個方法是使用JVM内置傳輸(in-JVM transport)。如果你知道Web Services和用戶端運作在同一個JVM上,你可以選擇使用本地傳輸,它可以大幅提升性能。在示例中的用戶端代碼,看以下指定服務端點URL的這行:

  String serviceUrl = "http://localhost:8080/websvc/services/Banking";

  替換為

  String serviceUrl = "xfire.local://Banking";

  你會看到性能上的明顯提高,因為它繞過了整個網絡層。

  局限性

  XFire有些重要的局限性你應該清楚:

•   ---開發Web Services的好的實踐是從WSDL開始。大部分的SOAP引擎提供了從WSDL生成服務stub的工具。XFire也提供了這樣一個工具。但是它是 基于注釋(annotations-based)的,是以需要J2SE5.0。對于仍堅持使用J2SE1.4.x的人來說,它不是一個令人拍手叫好的工 具,因為我們有很多其他方式來編寫用戶端,一個就是文章中示範的方式。

•   ---附件支援,它将會包含在未來發行的版本中。

•   ---易于學習的使用者向導。XFire團隊在這個方面還有很多工作需要做。

  結論

  Java目前的趨勢是簡化技術的使用。是以,我們正看到一波基于POJO的開發成就。同時,面向服務架構 (SOA,Services-oriented architecture)和Web Services已經變成了目前行業的熱點話題。XFire正是在這種情況下産生的。它能夠使POJO釋出為最少的Web Services,而隻需要付出最小化的努力。進而,它使希望使用這項技術的初級開發者的學習曲線變得平緩。同時,由于它相容最新标準和提供了豐富的 API,XFire為進階使用者提供了更多的大好機會。