問(wèn)一下.Net的開(kāi)發(fā)者,開(kāi)發(fā)Web Services有多困難?他們會(huì )被你的問(wèn)題逗樂(lè ),他們會(huì )告訴你所有步驟花費的時(shí)間不會(huì )超過(guò)一分鐘。再問(wèn)一下Java開(kāi)發(fā)者,運氣好的話(huà)你會(huì )碰到上面的回答,一般情況下,你會(huì )得到一個(gè)完全不同的答案。從Web Services引入到Java中至今已經(jīng)5年了,然而它仍然被認為是一門(mén)較新的技術(shù),一個(gè)主要的原因就是使用Java實(shí)現Web Services太困難了?,F在,隨著(zhù)新一代Web Services引擎XFire的發(fā)布,這種情況將會(huì )發(fā)生明顯的變化。使用XFire,你可以把Java類(lèi)方法發(fā)布為Web Services而不需要編寫(xiě)額外的代碼。在這篇文章中,你將會(huì )看到XFire使Web Services開(kāi)發(fā)變得多么容易和簡(jiǎn)單。
Web Services使我們能夠在網(wǎng)絡(luò )上建立分布式系統,應用程序組件可以通過(guò)任何平臺、任何語(yǔ)言和任何方式訪(fǎng)問(wèn)。無(wú)論應用程序如何開(kāi)發(fā),使用了什么語(yǔ)言,以及運行在什么操作系統平臺上,只要它作為Web Service,并且為協(xié)同解決問(wèn)題而設計,那么你的應用程序,以任何語(yǔ)言開(kāi)發(fā)或在任何平臺上,都可以利用它的服務(wù)。這是Web Service的主要概念。
為了實(shí)現Web Services的平臺無(wú)關(guān)性和實(shí)現訪(fǎng)問(wèn)獨立性,軟件行業(yè)需要遵循一些作為標準的技術(shù)。其中一些包括:
---XML:在Web Services環(huán)境中各層之間進(jìn)行傳遞的默認數據格式。
---SOAP:封裝和交換信息的默認協(xié)議。第一次被提出時(shí),它是只取Simple Object Access Protocol(簡(jiǎn)單對象訪(fǎng)問(wèn)協(xié)議)的首字母。但是現在SOAP更多被認為是一個(gè)特定的名詞,以它自己而命名,同樣很多人認為這是用詞不當:SOAP實(shí)際上不是用來(lái)訪(fǎng)問(wèn)對象的。另外,它也不再簡(jiǎn)單。
---WSDL(Web Services Description Language,Web Services描述語(yǔ)言):描述Web Services的語(yǔ)言。盡管基于XML并且可以被人理解,WSDL主要是由機器處理,由客戶(hù)端程序讀取和理解。
下面的高級層次圖表,基于WWW協(xié)會(huì )發(fā)布的“Web Services Architecture”(Web Services架構)文檔,顯示了這些技術(shù)在實(shí)際的工作環(huán)境中是如何發(fā)揮作用:
這個(gè)流程圖顯示了Web Services中的核心技術(shù)是如何工作的。
這里,Provider是提供服務(wù)的應用程序組件,Requester是使用服務(wù)的客戶(hù)端程序。很多其他技術(shù)也會(huì )參與到交互中,但是這個(gè)圖只顯示了在Web Services環(huán)境中必需的核心技術(shù)組件。
XFire是一個(gè)免費的開(kāi)源SOAP框架,它不僅可以極大方便地實(shí)現這樣一個(gè)環(huán)境,并且可以提供許多Web Services規范中高級特征,這些特征在多數的商業(yè)或者開(kāi)源工具都沒(méi)有提供。你要恰當的理解這些單詞:great ease and simplicity(非常輕松和簡(jiǎn)單)。你將會(huì )看到使用XFire創(chuàng )建Web Services是多么的簡(jiǎn)單。
一個(gè)簡(jiǎn)單的Java類(lèi)
我們的例子是一個(gè)銀行業(yè)應用程序,服務(wù)器是運行在J2SE1.4.2_07下的Apache Tomcat5.5.7。假定你已經(jīng)了解如何使用Java編寫(xiě)Web應用程序,并知道應該如何把它部署到Apache Tomcat服務(wù)器上。我們的Web應用程序非常簡(jiǎn)單;它只做一件事——將資金從一個(gè)賬戶(hù)轉到另外一個(gè)賬戶(hù)上。一個(gè)普通的Java類(lèi)BankingService包含了一個(gè)叫做transferFunds()的方法來(lái)為我們完成這項工作。它需要四個(gè)輸入參數:
代碼如下:
| package com.mybank.xfire.example; import java.text.NumberFormat; /** XFire WebServices sample implementation class. |
因為使用接口的設計是一個(gè)好的實(shí)踐,所以我們的Java類(lèi)也實(shí)現了一個(gè)稱(chēng)為IBankingService的接口。代碼十分簡(jiǎn)單:
| package com.mybank.xfire.example; public interface IBankingService { public String transferFunds( |
在實(shí)際實(shí)現中,這樣一個(gè)方法可能包括各種類(lèi)型的復雜調用、查詢(xún)和處理操作。但是我們的示例代碼已經(jīng)最小化了,以至于我們可以集中精力在主要目標上:把這個(gè)方法發(fā)布為Web Services。
你可以看到BankingService是一個(gè)普通的Java類(lèi),沒(méi)有任何代碼告訴我們它將會(huì )在Web Services中使用。好的,這里我們不需要增加任何東西。我們所有的工作都在部署描述符里完成。
Web應用的部署描述符
在Java中,Web應用程序通常需要至少一個(gè)部署描述符(叫做web.xml)對其進(jìn)行配置。XFire本身是一個(gè)基于servlet的應用程序。因此,我們需要增加必要的引用到描述符文件中。然后我們還必須配置將要創(chuàng )建的Web Services。我們使用一個(gè)稱(chēng)為services.xml的新文件來(lái)完成這件事。
web.xml
首先,修改web.xml。我們需要增加下面的XFire servlet相關(guān)的條目:
| <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
現在我們不得不說(shuō)一下我們的Web Services的由什么組成的了。這由一個(gè)叫做services.xml的文件完成,它存放在META-INF/xfire目錄下,而這整個(gè)目錄放在WEB-INF/classes文件夾中,它在Web應用程序的標準類(lèi)路徑中。這里是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的定義包含在 下一個(gè)子元素是<namespace>。任何合法的XML名字都是可以的。<namespace>用來(lái)唯一標識你的服務(wù)的各個(gè)參數。 <implementationClass>保存了實(shí)現方法的Java類(lèi)名。這是一個(gè)可選元素。如果上一個(gè)元素<serviceClass>包含了一個(gè)接口,那么相應的實(shí)現類(lèi)必須在這里指定。 就是這樣。我們的Web Services配置完成了。 XFire和其它類(lèi)庫 現在是最后一步了,需要得到所有必需的類(lèi)庫。我們怎樣得到它們呢?去XFire網(wǎng)站,下載xfire-distribution-1.0.zip,然后解壓到一個(gè)本地文件夾。復制下面的jar文件和它的庫文件夾到WEB-INF/lib中: 一切妥當。我們來(lái)部署和啟動(dòng)應用程序。為了部署示例應用,只需要復制websvc.war到Apache Tomcat的webapps文件夾中,再等待幾秒鐘。它將會(huì )自動(dòng)啟動(dòng)。這個(gè)應用的全部源代碼也包含在這個(gè)war文件中。我們的程序已經(jīng)準備作為一個(gè)Web Service了。 我們如何知道Web Service正在工作呢? 為了了解Web Service是否正在工作,我們需要測試。首先,我們測試來(lái)看WSDL是否可用。我們在瀏覽器中輸入URL。哪個(gè)URL?因為我們的應用程序的war文件是websvc.war,并且在services.xml中給出的服務(wù)名是Banking,WSDL的URL應該是:http://localhost:8080/websvc/services/Banking?wsdl。 請注意:URL的第一部分,例如,http://localhost:8080,可能會(huì )根據你的應用服務(wù)器不同而不同。無(wú)論怎樣,當你輸入URL后,將會(huì )看到一個(gè)XML文檔,它的根元素是 但是這個(gè)測試是不夠的??赡軙?huì )發(fā)生這種情況,可以看到WSDL,但是從客戶(hù)端程序可能會(huì )訪(fǎng)問(wèn)不到服務(wù)。因此為了核實(shí)服務(wù)是否可以訪(fǎng)問(wèn)了,我們必須使用一個(gè)客戶(hù)端進(jìn)行服務(wù)的實(shí)際調用來(lái)進(jìn)行一個(gè)真正的測試。 開(kāi)發(fā)一個(gè)客戶(hù)端 你可以使用任何的SOAP工具創(chuàng )建客戶(hù)端,例如,.Net或者Apache Axis,有很多種方法:使用從WSDL產(chǎn)生的stubs,使用動(dòng)態(tài)代理,等等。在例子中,我們使用一個(gè)動(dòng)態(tài)代理,以一個(gè)簡(jiǎn)單的Servlet形式,叫做WsClient.java。為了保持代碼兩最小,所有在屏幕顯示的元素都放在了doGet()方法中。對Web Service的實(shí)際調用由callWebService()方法完成,它相當地簡(jiǎn)單。和下面的類(lèi)似: /* Call the Web service //Return the response 這個(gè)代碼是如何工作的呢?我來(lái)解釋一下:首先,我們創(chuàng )建一個(gè)服務(wù)模型,它包含服務(wù)的說(shuō)明——換句話(huà)說(shuō),就是服務(wù)的元數據。我們使用XFire的ObjectServiceFactory從IBankingService.class接口創(chuàng )建這個(gè)模型。 接著(zhù),為XFire獲得一個(gè)代理工廠(chǎng)對象,它包含了常規的代碼,也相當地簡(jiǎn)單和易懂。這一步中沒(méi)有任何特定應用的東西。從這個(gè)proxyFactory,使用服務(wù)模型和服務(wù)端點(diǎn)URL(用來(lái)獲得WSDL),我們可以得到一個(gè)服務(wù)的本地代理。 就是它了。這個(gè)代理就是實(shí)際的客戶(hù)端?,F在,我們可以調用它的transferFunds()方法來(lái)得到我們需要的Web Service。 一旦示例應用發(fā)布并啟動(dòng),就可以嘗試servlet URL: http://localhost:8080/websvc/ws。 這個(gè)Servlet使用默認參數來(lái)調用Web Service和顯示接收到的響應。頁(yè)面的最后兩行應該讀取: Response Received 現在你可以確定Web Service已經(jīng)發(fā)布并且在運行中了。 為了嘗試不同的輸入值,你可以使用完整的URL,例如: http://localhost:8080/websvc/ws?from=11-2345&to=77-9876&amt=250.00&cur=EUR。 基本的Web Services開(kāi)發(fā)步驟清單 這個(gè)清單總結了將一個(gè)Java方法發(fā)布為Web Service所必須的步驟: 這就是所有需要的步驟,是的,相當簡(jiǎn)單。 XFire的其他高級特性 XFire的使用可能比較簡(jiǎn)單,但是在特性和功能性上,它卻占據著(zhù)領(lǐng)導者的位置。下面是它的高級特性: 最重要的是,XFire屬于新一代Web Services引擎。不僅僅是營(yíng)銷(xiāo)用語(yǔ),“新一代”有一些重要的意義。Apache Axis是第一代Java語(yǔ)言的Web Services引擎,已經(jīng)成為了所有后來(lái)工具的參考標準。在過(guò)去的幾年里,Axis以及這些其它的工具已經(jīng)在很多生產(chǎn)環(huán)境中進(jìn)行了實(shí)地測試。從中得出的一個(gè)關(guān)鍵的問(wèn)題就是Web Services并不最適合RPC類(lèi)型的通信。對于性能和效率,面向文檔的消息形式是最好的方式。但是Apache Axis和很多其他的Web Services引擎都被設計成了面向RPC的(盡管它們支持文檔形式)?,F在,整個(gè)行業(yè)正在開(kāi)發(fā)新一代的SOAP引擎,設計為面向文檔的。Apache已經(jīng)宣布結束舊版本的Axis引擎開(kāi)發(fā),現在專(zhuān)注于A(yíng)xis2,現在它的預發(fā)布版本是0.95。XFire在今年的2月份發(fā)布了它的第一個(gè)產(chǎn)品版本(1.0)。它的下一個(gè)版本(1.1)僅僅在幾個(gè)星期之后就進(jìn)行了發(fā)布。 性能 Web Services需要消耗很多資源,但是性能方面它們不是那么引人注目。XFire打破了這種趨勢。它消耗更少的內存(部分因為 StAX的使用),但是表現卻比多數可比較的SOAP引擎出色。你可以在資源中提供的鏈接中看到比較的結果。 此外,XFire還提供了各種方法來(lái)進(jìn)一步優(yōu)化性能。一個(gè)方法是使用JVM內置傳輸(in-JVM transport)。如果你知道Web Services和客戶(hù)端運行在同一個(gè)JVM上,你可以選擇使用本地傳輸,它可以大幅提升性能。在示例中的客戶(hù)端代碼,看以下指定服務(wù)端點(diǎn)URL的這行: String serviceUrl = "http://localhost:8080/websvc/services/Banking"; 替換為 String serviceUrl = "xfire.local://Banking"; 你會(huì )看到性能上的明顯提高,因為它繞過(guò)了整個(gè)網(wǎng)絡(luò )層。 局限性 XFire有些重要的局限性你應該清楚: 結論 Java當前的趨勢是簡(jiǎn)化技術(shù)的使用。因此,我們正看到一波基于POJO的開(kāi)發(fā)成就。同時(shí),面向服務(wù)架構(SOA,Services-oriented architecture)和Web Services已經(jīng)變成了當前行業(yè)的熱點(diǎn)話(huà)題。XFire正是在這種情況下產(chǎn)生的。它能夠使POJO發(fā)布為最少的Web Services,而只需要付出最小化的努力。從而,它使希望使用這項技術(shù)的初級開(kāi)發(fā)者的學(xué)習曲線(xiàn)變得平緩。同時(shí),由于它兼容最新標準和提供了豐富的API,XFire為高級用戶(hù)提供了更多的大好機會(huì )。 版權聲明:Techtarget獲Matrix授權發(fā)布,如需轉載請聯(lián)系Matrix
<serviceClass>元素包含了Java類(lèi)的名字,它指定了方法簽名。在我們的例子中,它是接口IBankingService。如果Java類(lèi)沒(méi)有實(shí)現任何接口,你就需要把類(lèi)的名字放在這里。在你的Java類(lèi)或者接口中可能有幾個(gè)方法。只需要一個(gè)入口把它們全部發(fā)布為Web Services。
*
*/
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 serviceResponse;
}
COMPLETED: CDN$ 500.00 was successfully transferred from A/C# 11111-01234 to A/C# 99999-05678
作者:Shahid Ahmed ;mydeman
原文:http://www.javaworld.com/javaworld/jw-05-2006/jw-0501-xfire.html
Matrix:http://www.matrix.org.cn/resource/article/2006-09-24/XFire_6bd1061c-4bc6-11db-978f-43b3336b7e51.html
聯(lián)系客服