【XFire:简化Web服务开发】android 开发教程
Web服务很难用Java来实现。而如今随着XFire新一代Web服务引擎的发布,这种情况有望出现重大变化。 如果问问.Net开发人员开发Web服务有多难,他们可能会觉得这样的问题很可笑,可能会说所需步骤用不了一分钟。再问问Java开发人员,十有八九会得到全然不同的答复。Web服务在Java领域推出已有五个年头。不过,它仍被认为是比较新的技术之一,主要原因就是Web服务很难用Java来实现。如今随着XFire新一代Web服务引擎的发布,这种情况有望出现重大变化。如果使用XFire,无须另外编写代码,就可以把Java类方法作为Web服务来发布。本文将介绍XFire如何让Web服务开发成为轻而易举的事。
Web服务使我们能够构建分布式系统,在这种环境里面,可通过与平台、语言和实现无关的方式,访问网络上的应用组件。某个应用如何开发、采用哪种语言、或者在哪款操作系统平台上运行,这些都不重要。如果应用作为Web服务存在、旨在解决互操作性问题,那么不管用哪种语言或者平台开发而成,它都能够利用服务。这就是Web服务的主要概念。
为了能够通过与平台和实现无关的方式访问Web服务,软件行业已经就几项技术作为标准达成了一致。其中一些如下:
● XML:可以跨Web服务环境的所有层使用的默认数据格式。
● SOAP:用于封装及交换消息的默认协议。首次引入时,它是简单对象访问协议的缩略语。但如今SOAP被认为是专有名词,因为大多数人现在认识到名称不当:SOAP其实并不是用来访问对象的。另外,它也不再是简单的。
● WSDL(Web服务描述语言 ):描述Web服务的语言。虽然基于XML、能够被人理解,但WSDL主要供机器使用,由客户程序来读取及理解。
表明了所有上述技术在工作环境当中的相互关系。其中,提供者(Provider)是提供服务的应用组件,而请求者(Requester)是使用服务的客户程序。其他许多技术可能会参与这些关系,但该图表明了Web服务环境中不可或缺的核心组件。
XFire是免费、开放源代码的SOAP框架,它不但能够轻而易举地实现这类环境,还能够提供许多Web服务规范确认的高级特性,但目前还没有出现在大多数商用或者开放源代码工具里面。
如果Web应用拥有Java类,又需要它的方法可以作为Web服务来发布,那么如果使用XFire,可能用不着多编写一行Java代码。只要处理部署描述文件(deployment descriptors),就能获得Web服务。我们不妨看一个示例。
简单的Java类
我们的示例是放在Apache Tomcat 5.5.7上的银行业务应用,在J2SE 1.4.2_07环境下运行。我们假定读者朋友已经知道了如何用Java编写Web应用,而且部署到了Apache Tomcat服务器上。我们的Web应用很简单,它只完成一项工作:把资金从一个账户转移到另一个账户。普通的Java类BankingService含有名为transferFunds()的方法,它为我们做这项工作。它需要四个输入参数:String fromAccount、String toAccount、double amount、String currency。代码如下:
package com.mybank.xfire.example;
import java.text.NumberFormat;
import java.text.DecimalFormat;
/** XFire WebServices示例实现类
*/
public class BankingService implements IBankingService {
//默认构造函数
public BankingService(){
}
/** 把资金从一个帐户转移到另一个帐户
*/
public String transferFunds(String fromAccount, String toAccount, double amount, String currency){
String statusMessage = "";
//调用业务对象及其他组件以完成这项工作。
//然后创建状态消息并返回。
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;
}
}
在这里有没有看到任何异常?可能没有,除了公有的默认构造函数外。默认构造函数不可少,不然,XFire没法为类创建实例。因为使用接口进行设计是好的做法,我们的Java类也实现了名为IBankingService的接口。代码很简单:
package com.mybank.xfire.example;
public interface IBankingService {
public String transferFunds(
String fromAccount, String toAccount, double amount, String currency);
}
在实际中,这类方法可能包括各种复杂的调用、查询和处理操作。但我们的示例代码非常简短,那样我们可以专注于主要目标:把该方法作为Web服务来发布。
可以看到,BankingService是普通的Java类,没有任何代码告诉它是不是应当用于Web服务中。这里我们不需要添加任何代码。我们的所有工作将在部署描述文件里面完成。
Web应用的部署描述文件
在Java中,通常使用至少一个部署描述文件(名为web.xml)来配置Web应用。XFire本身是基于服务器小程序的应用。因而,我们需要为该文件添加必要的引用。然后我们必须配置创建的Web服务。我们将使用名为services.xml的新文件来完成这项工作。
● web.xml
首先,我们先来处理web.xml。我们需要添加与XFire服务器小程序有关的下列条目:
XFireServlet
XFire Servlet
org.codehaus.xfire.transport.http.XfireConfigurableServlet
XFireServlet
/servlet/XFireServlet/*
XFireServlet
/services/*
● services.xml
现在我们必须表明我们的Web服务由什么组成。这一步在名为services.xml的文件里面完成,该文件放在META-INF/xfire目录下。这整个目录又放在WEB-INF/classes文件夹下,而该文件夹位于Web应用的标准类路径。以下是services.xml里面的基本配置条目:
Banking
mybank
com.mybank.xfire.example.IBankingService
com.mybank.xfire.example.BankingService
让我们看看现在有了什么。Web服务的定义包括在元素里面,该元素含有几个子元素。第一个子元素是,它可以是任何有效的XML名称。它将会被客户程序及其他组件用来确定服务的位置。譬如说,服务可供使用后,可以通过浏览器用这个名称来查看WSDL。
下一个子元素是。任何有效的XML名称都可以。 将用来以独特方式确认服务的不同参数。
元素含有指定了方法签名的Java类名称。在我们的示例中,它是接口IBankingService。如果Java类没有实现任何接口,可以把该类的名称放在这里。Java类或者接口可能有几个方法。只需要一个条目就可以把它们全部作为Web服务来发布。
含有拥有方法实现的Java类名称。这是一个可选元素。如果前一个元素含有接口,相应的实现类就必须在这里命名。
Web服务的配置工作到此宣告完成。
XFire及其他库
现在我们进入最后一步:获得所有必要的库文件。进入XFire网站,下载xfire-distribution-1.0.zip,然后解压缩到本地文件夹。把下列jar文件从发行版本和库目录拷贝到WEB-INFlib下: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环境中的web应用目录,等几秒钟时间。它会自动启动。应用的全部源代码也包含在该war文件里面。现在我们的程序为成为Web服务做好了准备。
如何知道Web服务可正常工作?
为了看看Web服务是否在正常工作,就必须进行测试。先测试查看有没有WSDL。往浏览器上输入URL。因为我们应用的war文件是websvc.war、services.xml给出的服务名称是Banking,所以WSDL的URL是:
https://localhost:8080/websvc/services/Banking wsdl。
请注意:URL的第一个部分即https://localhost:8080可能会有所不同,这具体取决于应用服务器的设置。不管怎样,输入URL后,都会看到根元素是的XML文档。该文档被称为是服务的WSDL。如果能看到它,证明应用已经作为Web服务而存在。
但这种测试还不够。可能会出现这种情况:可能看到了WSDL,却无法从客户端访问服务。所以为了证明服务是不是可供使用,我们必须使用实际调用服务的客户程序来进行实际测试。
开发客户程序
可以使用任何SOAP工具,如.Net或者Apache Axis来创建客户程序,方法有好多种:使用由WSDL生成的占位模块(stub),或者使用动态代理系统等等。在示例中,我们在名为WsClient.java的简单的服务器小程序中使用了动态代理系统。为了尽量减少编写代码的工作量,所有的屏幕构建元素都放在doGet()方法里面。实际调用Web服务的操作在callWebService()方法里面进行,这相当简单。代码如下:
/* 调用Web服务
*
*/
public String callWebService(
String fromAccount, String toAccount, double amount, String currency)
throws MalformedURLException, Exception {
//创建服务的元数据
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 = "https://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());
}
//调用服务
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;
}
这段代码实现了怎样的操作?不妨解释一下:首先,我们创建了服务模型,该模型包含服务规范,换句话说,就是服务的元数据。我们使用XFire的ObjectServiceFactory,利用接口IBankingService.class创建了该模型。
下一步就是获得XFire的代理工厂对象,这需要例行代码,但相当简单、直观。这一步没有应用特定的任何东西。我们通过proxyFactory,使用服务模型和服务端点URL(用来获得WSDL),就可以获得该服务的本地代理系统。该代理系统就是实际的客户程序。现在我们可以调用transferFunds()方法来获得所需的Web服务。
一旦示例应用加以部署及启动,不妨试试服务器小程序的URL: https://localhost:8080/websvc/ws。服务器小程序使用默认参数来调用Web服务、显示收到的响应。页面的最后两行应当这样:
Response Received
COMPLETED: CDN$ 500.00 was successfully transferred from A/C# 11111-01234 to A/C# 99999-05678
现在可以肯定:Web服务在正常使用。为了用不同的输入值进行尝试,还可以使用类似以下的完整的URL:
https://localhost:8080/websvc/ws?from=11-2345&to=77-9876&amt=250.00&cur=EUR.
XFire的其他高级特性
XFire也具有高级的特性和功能。部分高级特性如下:
● 本地数据绑定功能。支持普通Java对象(POJO)、XMLBeans、面向XML绑定的Java架构(JAXB)和Castor等。数据绑定指定了发送至Web服务的XML请求以及返回的XML响应如何映射成Java对象。
● 使用用于XML的流式API(StAX)处理XML文档。与文档对象模型(DOM)的基于树形的方法以及用于XML的简单API(SAX)的事件驱动方法相比,StAX使用了基于拉取的机制,这不但大大加快了速度,还提高了内存的使用效率。
● 支持各种传输协议,譬如HTTP、Java消息服务(JMS)和Java虚拟机内部传输(in-JVM transport)。
● 嵌入功能,这是XFire的主要优点之一。可以把这个SOAP引擎嵌入到应用当中,完全隐藏XFire特定的所有引用,因为所有配置都是程序驱动的。
● 具有丰富的API,这样一来,非常容易定制,让开发人员可以在需要时,在不同阶段截获请求,并且进行处理。
● 符合诸多最新标准,譬如SOAP 1.1(没有编码的远程过程调用即RPC)和1.2、WSDL 1.1、Web服务互操作性组织的Basic Profile 1.0、Web服务寻址规范和Web服务安全标准。
最重要的是,XFire属于新一代的Web服务引擎。“新一代”不只是营销术语,它具有一定的重要意义。Apache Axis是Java领域最早的Web服务引擎之一,已成为后来问世的所有工具的衡量基准。在过去的几年里,Axis及其他这些工具已在许多生产环境进行了现场测试。获得的重要经验教训之一就是,Web服务并非最适合RPC类型的通信。出于性能和效率的考虑,面向文档的消息传输类型的通信才是出路。但Apache Axi及其他大多数Web服务引擎在设计上却是面向RPC的(不过它们支持文档类型)。业界现正在开发新一代的SOAP引擎,它们在设计上是面向文档的。Apache已经宣布停止开发旧版的Axis引擎,现正在开发Axis2(最新发布前版本为0.95)。XFire在今年2月推出了第一个生产版本(1.0)。
性能和局限
Web服务使用许多资源,但它们的性能并不高。XFire打破了这个传统。与同类的SOAP引擎相比,XFire使用的内存大大减少(一方面是由于使用StAX),而性能却大大提高。
另外,XFire还提供了进一步优化性能的几种方法。方法之一就是使用Java虚拟机内部传输。如果知道Web服务与客户程序在同一个Java虚拟机里面运行,就可以选择使用本地传输,这样可以高速传输服务。在示例的客户程序代码当中,请注意指定了服务端点URL的那一行:
String serviceUrl = "https://localhost:8080/websvc/services/Banking";
被换成了:
String serviceUrl = "xfire.local://Banking";
可以看到,性能的大幅度提升是因为绕开了整个网络层。
不过,XFire也具有一些严重的局限性,同样应当引起注意:
● 开发Web服务的一个好的做法就是,从WSDL开始着手。大多数SOAP引擎提供了利用WSDL创建服务占位模块的工具。XFire也提供了这样一个工具。但它需要使用注解,因而需要J2SE 5.0。这对仍坚持使用J2SE 1.4.X的人来说并不受欢迎,因为他们用其他方法来编写客户程序,本文给出的示例就表明了一种方法。
● 缺少支持附件的功能,不过将来的版本一定能支持该功能。
● 缺少简单易懂的用户指南,XFire开发队伍在这方面有许多工作要做。
链接:把Java方法作为Web服务发布的步骤
1、 检查Java类的方法和默认构造函数都是公有的。
2、为web.xml添加与XFire服务器小程序有关的条目。
3、创建services.xml,并把它放在WEB-INF/classes/META-INF/xfire目录下。
4、把XFire和第三方的库添加到Web应用的WEB-INF/lib目录下。
