IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Rational  >

使用 Rational Application Developer V7.0 开发 JAX-WS Web 服务

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

样例代码


李 凌 (liling@cn.ibm.com), 软件工程师, IBM

2008 年 4 月 30 日

IBM Rational Application Developer V7.0 (以下简称 RAD)是用于构建 Java SE 和 Java EE 应用程序的集成开发平台。RAD V7.0.0.3 提供了对开发 JAX-WS (Java API for XML-Based Web Services) Web 服务的支持。本文详细介绍了使用 RAD 开发、部署和测试 JAX-WS Web 服务的方法,并通过示例程序展现了 JAX-WS 的新特性。

JAX-WS 简介

JAX-WS 2.0 是继 JAX-RPC 1.1 之后的下一代 Web 服务标准,它提供了完整的 Web 服务协议栈,可显著减少开发和部署 Web 服务所需要的工作。JAX-WS 主要支持以下标准:

    • Java Architecture for XML Binding (JAXB) 2.0
    • Simple Object access protocol (SOAP) 1.2,以及 SOAP 1.1
    • Web Services Description Language (WSDL) 2.0,以及 WSDL 1.1
    • WS-I Basic Profile (BP) 1.1
    • SOAP with Attachments API for Java (SAAJ) 1.3

相对于 JAX-RPC,JAX-WS 拥有以下一些新特性:

    • 提供了用于将传统 Java 对象(Plain Old Java Object,POJO)类转换为 Web 服务的 Annotation 库,从而加速了 Web 服务的开发工作。
    • 提供了异步编程模型,支持对 Web 服务的异步调用。
    • 支持消息传输优化机制(Message Transmission Optimization Mechanism,MTOM),有效提高使用 SOAP 协议传输二进制格式附件的效率。

本文借助 RAD 集成开发平台,首先使用 Annotation 方式实现一个简单的 Web 服务端点,然后根据该服务端点的 WSDL 文件构建支持异步调用的 Web 服务客户机,最后在客户机与服务端点之间实现 MTOM 方式的二进制附件传输,并对此进行测试。





回页首


建立 RAD 开发环境

RAD 在 V7.0.0.3 以及后续版本中提供了对开发 JAX-WS Web 服务的支持。它包含了 Web Services Feature Pack(简称 WSFP)和 IBM WebSphere Application Server V6.1 Feature Pack for Web Services(简称 WASFP)这两个组件。WSFP 引入了一系列最新的 Web 服务标准,来支持 JAX-WS Web 服务的开发,这些标准包括 Web Services Reliable Messaging (WS-RM)、Web Services Addressing (WS-Addressing)、SOAP MTOM、JAXB 2.0、SOAP 1.2、SAAJ 1.3 等。WASFP 在 WebSphere Application Server V6.1 的基础上,提供了部署 JAX-WS Web 服务所需的运行时环境。

安装 WSFP 和 WASFP

要安装 WSFP 和 WASFP 这两个升级包,必须首先安装 RAD 的 V7.0.0.3 或更高版本(目前的最新版本是 7.0.0.5)的升级程序。

首次安装 RAD 时,可以通过在 IBM Installation Manager 的 Install Packages 界面上选择 Check for updates 来同时安装 V7.0.0.3 或更高版本的升级包,如图 1 所示。


图 1. 安装 V7.0.0.3 或更高版本的升级包
安装 V7.0.0.3 或更高版本的升级包

如果已经安装了 RAD,并且它的版本低于 V7.0.0.3,那么需要对 RAD 进行升级,以安装 WSFP 和 WASFP。选择 IBM Installation Manager 上的 Update Packages wizard 即可将 RAD 升级到 V7.0.0.3 或更高版本。

安装完 RAD 的 V7.0.0.3 升级包后,运行 IBM Installation Manager 上的 Modify Packages wizard,并在安装过程中的 Features 选项卡上选择 Web Services Feature Pack 和 IBM WebSphere Application Server V6.1 Feature Pack for Web Services 这两个组件,来完成安装,如图 2 所示。


图 2. 选择组件
选择组件

配置 RAD 开发环境

在完成 WASFP 组件的安装之后,安装向导会自动创建一个使用该组件的名称为 AppSrvWSFP01 的 WebSphere Application Server 概要文件,因此需要在 RAD 中新建一个名为 WAS WSFP 的服务器定义来使用 AppSrvWSFP01 概要文件,该服务器定义将被用于测试 JAX-WS 应用程序。

至此,支持 JAX-WS 的 RAD 集成开发环境构建完毕。





回页首


使用 Annotation 开发 Web 服务端点

JAX-WS Annotation 是 Web Services Metadata for the Java Platform 规范(JSR-181)的一部分。使用 Annotation 可以方便地通过添加注释的方式来将一个 Java 类文件升级为 Web 服务,而不需要编写任何部署描述符,如 web.xml 或者 webservices.xml,也不需要手工创建 WSDL 文件。在 Web 服务部署期间,服务器将自动地生成或者更新这些描述符。

实现 Web 服务端点

本节将介绍如何在 RAD 中建立 JAX-WS Web 服务工程,并构建一个最简单的 Web 服务。

首先,依次点击 RAD 的“File”->“New”->“Dynamic Web Project”,创建一个名为“TestWS”的 Web 工程,同时为该 Web 工程新建一个名为“TestWSEAR”的 J2EE 工程,以方便测试。注意,在创建过程中的 Project Facets 页面,一定要选取 WebSphere 6.1 Feature Pack for Web Services 1.0。然后,再次创建一个名为“TestWSClient”的 Web 工程,同时将该 Web 工程关联到 TestWSEAR 工程中,以便后续创建 JAX-WS 客户机时使用。

在 TestWS 工程中添加一个 Java 类,代码如清单 1 所示。这段代码展示了提供 echoImage(byte[]) 函数的 JAX-WS Web 服务的最简单实现。该 Web 服务简单地将收到的字节数组回应到客户端。本文涉及到的所有源代码已经打包为 TestWSEAR.ear 文件,可从文章末尾给出的链接下载。


清单 1
                
// com.sample.service.Echo.java
package com.sample.service;
import javax.jws.WebService;
@WebService()
public class Echo {
public byte[] echo(byte[] bytes) {
 System.out.println("service done.");
 return bytes;
}
}

可以看到,与普通的 Java 类相比,该 Web 服务实现类仅仅是在类定义前增加了 @WebService 注释,它将类定义成为 Web 服务端点。在部署期间,服务器将在 TestWS 工程的 .apt_generated 文件夹中生成 Echo 和 EchoResonse 这两个辅助类,并根据 Annotation 自动更新相应的部署描述符文件。

此外,还可以在类定义前添加 @SOAPBinding 注释,来指定 Web 服务所绑定的 SOAP 消息协议类型;或是在方法定义前添加 @WebMethod 注释,来指定是否将该 Java 方法对外暴露为 Web 服务的某项操作,等等。这些 Annotation 可以很好的取代部署描述符的作用,对 Web 服务进行定义,大大简化了 Web 服务的开发工作。

在 JAX-WS 中,服务端点接口(SEI)将隐含于服务实现类中,因此这个服务类不需要额外实现任何接口;同时,JAX-WS 也不需要 jaxrpc-mapping 文件,因为它使用 JAXB 进行所有数据的绑定。

部署 Web 服务端点

在 RAD 的“Servers”面板上选中 WAS WSFP 服务器,点击右键选取“Start”启动该服务器;待服务器启动完成后,点击右键选取“Add and Remove Projects”,将 TestWSEAR 工程部署到服务器。等待部署完成,在 Web 浏览器中输入 http://localhost:9081/TestWS/EchoService?wsdl,如果成功地部署了该服务,并且该服务正在运行,那么服务器会生成并返回该服务的 WSDL 文件。

在后续的章节中将介绍如何开发一个支持异步调用的客户端来对该 Web 服务进行进一步的测试。





回页首


开发支持异步调用的 Web 服务客户端

由于 Web 服务调用是通过网络来实现的,这种调用所花费的时间是无法预测的。交互式客户端或是某些对性能要求较高的客户端,由于必须等待 Web 服务的响应而严重地影响了它们的性能和用户体验。为了避免这种性能降低,JAX-WS 提供了新的支持异步调用的 Web 服务客户机 API(客户端代理)。借助该 API,应用程序开发人员不再需要自己创建线程,而是依赖 JAX-WS 异步客户机运行时为他们管理需要长时间运行的 Web 服务调用。当客户端程序使用 JAX-WS 客户机异步调用 Web 服务时,客户机会发送请求给 Web 服务端,并立即返回到客户端程序,这样客户端程序可以先继续处理后续的工作,而不用等待 Web 服务端返回结果。

生成 JAX-WS 客户端代理类

RAD 支持根据 JAX-WS Web 服务的 WSDL 文件自动生成客户端代理类。具体方法如下:在 Project Explorer 面板的 JAX-WS Web Services 文件夹,右键点击 TestWS:{http://test.jaxws.com/}EchoService,选择 Generate Client;然后在出现的 Web Serveices 面板(图 3)中选择 Server 为 WAS WSFP,选择 Web service runtime 为 IBM Websphere JAX-WS,选择 Client project 为 TestWSClient,最后勾选 Monitor the Web service,点击 Next 继续。


图 3. Web Serveices 面板
Web Serveices 面板

在出现的 Client Configuration 面板(图 4)中勾选 Enable asynchronous invocation for generated client 以生成支持异步调用的客户机,并在 Target package 输入 com.sample.stub,最后点击 Finish 生成代理类文件。下一节介绍的客户端程序将通过调用这些代理类来访问 Web 服务。


图 4. Client Configuration 面板
Client Configuration 面板

开发客户端程序

本节介绍的客户端程序以 HttpServlet 的方式,借助 RAD 生成的 Web 服务代理类,分别实现了对 EchoService Web 服务的同步调用方法 syncRequest()、轮询方式异步调用方法 pollRequest() 和回调方式异步调用方法 feedbackRequest();每个方法都发起了 2 次对 EchoService 的调用,并将服务返回的响应内容和方法执行时间显示在浏览器页面上。

同步调用

首先介绍 syncRequest() 同步调用方法的实现,见清单 2。在该方法中,依次对 EchoService 发起两次调用,每次调用时线程将阻塞等待 Web 服务返回结果,每次得到结果后就将返回值输出在浏览器页面上;最后输出该方法的总计执行时间。


清单 2
                
// com.sample.client.Client.java
private void syncRequest() throws IOException{
pw.println("Web service request 1 is sent, wait response...<br>");
pw.flush();
result = port.echo(req1.getBytes());
pw.write("<b>"+new String(result)+"</b>");
pw.flush();
wait(2000);
pw.println("Web service request 2 is sent, wait response...<br>");
pw.flush();
result = port.echo(req2.getBytes());
pw.write("<b>"+new String(result)+"</b>");
pw.flush();
}

可以通过链接 http://localhost:9081/TestWSClient/Client?type=sync 来测试该同步调用方法。运行结果如图 5 所示。由于对 Web 服务的调用是串行的,syncRequest() 方法的总计执行时间是两次 Web 服务响应时间之和。


图 5. 测试该同步调用方法
测试该同步调用方法

轮询模式异步调用

JAX-WS 提供了轮询模式和回调模式这两种异步调用模型。在轮询模型中,客户端程序发出调用,然后在对应的 Response 对象上不断轮询,以便在 Web 服务端给出响应后获取到调用的结果;Response 对象用于监视 Web 服务请求的状态,判断请求是否完成,并获取请求的结果。

此客户端程序以 pollRequest() 方法(清单 3)实现了轮询方式异步调用 EchoService。在该方法中也是依次对 EchoService 发起两次调用,但并不阻塞等待返回结果,而是在两次调用都发出之后,在各自的 Response 对象上调用 get() 方法来获取结果。调用 get() 方法时,如果 Web 服务的响应已经返回,那么将立即获取到返回值;否则,线程会在 get() 方法上一直等待到响应返回为止。


清单 3
                
// com.sample.client.Client.java
private void pollRequest() {
pw.println("Web service request 1 is sent, wait response...<br>");
pw.flush();
Response resp1=port.echoAsync(req1.getBytes());
wait(2000);
pw.println("Web service request 2 is sent, wait response...<br>");
pw.flush();
Response resp2=port.echoAsync(req2.getBytes());
try {
result=((EchoResponse)resp1.get()).getReturn();
pw.write("<b>"+new String(result)+"</b>");
pw.flush();
result=((EchoResponse)resp2.get()).getReturn();
pw.write("<b>"+new String(result)+"</b>");
pw.flush();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}

可以通过链接 http://localhost:9081/TestWSClient/Client?type=poll 来测试该轮询调用方法。运行结果如图 6 所示。从测试结果来看,采用轮询模式,客户端不用等待结果的返回,基本上实现了对 Web 服务的并发调用,显著提高了客户端程序的性能。


图 6. 运行结果
运行结果

回调模式异步调用

在回调模型中,JAX-WS 提供了 AsynchHandler 这个回调处理接口来接收并处理传入的 Response 对象。当响应到达,Response 对象被传入时,AsynchHandler 中的 handleResponse(Response) 方法将被执行,可以在 handleResponse(Response) 方法中编写相应代码从 Response 中获取请求结果。

如清单 4 所示,callbackRequest() 方法中也发起了两个异步 Web 服务调用,当调用结果返回时,handleResponse(Response) 方法将被执行,并通过调用 get() 方法获取到类型为 EchoResponse 的响应对象,最后调用 getReturn() 方法即可获取到返回值。


清单 4
                
// com.sample.client.Client.java
private void callbackRequest() throws IOException{
pw.println("Web service request 1 is sent, wait response...<br>");
pw.flush();
port.echoAsync(req1.getBytes(),this);
wait(2000);
pw.println("Web service request 2 is sent, wait response...<br>");
pw.flush();
port.echoAsync(req2.getBytes(),this);
}
public void handleResponse(Response resp) {
try {
result = ((EchoResponse)resp.get()).getReturn();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} 
}

可以通过链接 http://localhost:9081/TestWSClient/Client?type=callback 来测试该回调方法。运行结果如图 7 所示。回调模式和轮询模式的性能相近,开发人员可以根据实际情况合理选择。


图 7. 运行结果
运行结果

使用异步消息交换

默认情况下,上面提到的异步调用模式都没有实现消息级的异步,其本质均是借助 java.util.concurrent.Executor 类在编程模型上使用多线程的方式达到异步调用的目的。也就是说,Web 服务调用过程中的请求和响应并不是异步的。要实现消息级的异步调用,需要在客户端代理类的请求上下文中设置属性 com.ibm.websphere.webservices.use.async.mep 为 true,详细设置方法参见清单 5。


清单 5
                
//com.sample.stub.EchoService.java
 @WebEndpoint(name = "EchoPort")
 public Echo getEchoPort() {
 Echo echo=(Echo)super.getPort(new QName("http://service.sample.com/", 
                               "EchoPort"), Echo.class);
 Map<String, Object> rc = ((BindingProvider) echo).getRequestContext();
 rc.put("com.ibm.websphere.webservices.use.async.mep", Boolean.TRUE);
 return echo;
 }

设置该属性之后,客户端与服务器之间的消息交换将采用异步方式进行。Web 服务的请求消息中将包含一个 WS-Addressing 头,该头域提供了额外的路由信息,以帮助异步消息交换的顺利进行。这时,客户端会在某一端口监听,以等待响应的到来;客户端的地址和监听端口信息被记录到请求的 WS-Addressing 头域;当 Web 服务端收到请求后,会将响应发送到请求中 WS-Addressing 所记录的 ReplyTo 地址。客户端将一直监听直到响应到来,并不会因为超时而退出监听,但可以使用 Response.cancel() 方法(轮询模式)或 Future.cancel() 方法(回调模式)来停止监听。需要注意的是,在 Windows 平台下,ReplyTo 字段所记录的 URL 地址是以客户端的主机名为标识的,如果 Web 服务端不能解析该主机名,那么响应将不能到达客户端。为避免出现这个问题,可以在 Java 虚拟机中添加 -Dcom.ibm.websphere.webservices.transportEPRInIPAddr=yes 这个通用 JVM 参数,从而强制客户端在发送请求时以 IP 地址作为 ReplyTo 字段的标识。





回页首


为客户机和服务端点实现 MTOM

在 Web 服务的实现中,经常需要在 SOAP 报文中携带各种二进制格式的附件(如图像、文档等)一起传输。然而,SOAP 是一种基于 XML 的文本协议,只能使用 ASCII 组成的文本来表示数据,无法在报文中直接包含二进制格式的附件。

在 JAX-RPC 中使用 SOAP 发送二进制数据有两种方法,一种是把二进制数据通过 Base64 编码为 ASCII 格式,另一种是以 MIME 附件的方式发送。

SOAP 1.0 所支持的 Base64 编码方式简单易用,但是生成的 ASCII 文本大小相对于原始二进制格式有 30% 左右的增长。此外,对二进制文件进行 Base64 编解码将消耗大量的 CPU 资源。因此,这种方式只适用于发送比较小的二进制数据。

为了改进 Base64 编码的附件发送方式,SOAP 1.1 增加了对 SOAP Messages with Attachments (SwA) 规范的支持,SwA 将附件置于 SOAP 消息主体之外,基于 MIME 技术实现了 SOAP 消息同 SOAP 附件的封装。这在一定程度上解决了 Base64 编码所带来的性能问题,但这会导致大量的互操作性问题。

为了进一步改进二进制数据传输的性能和互操作性,JAX-WS 增加了对 MTOM 规范的支持。MTOM 是 W3C 所开发的一个标准,它通过 XOP(XML-binary Optimized Packaging)方式来实现二进制数据的传输。XOP 使用 MIME 将原始二进制数据引入到 XML 文档中,避免了 Base64 编码所带来的性能开销;同时借助 xop:Include 元素显式地将内容与附件关联起来,使得二进制数据的处理方式与文本数据的处理方式一致,避免了在 SwA 中存在的歧义性,较好地解决了互操作性问题。MTOM 可以优化二进制数据的传输,它会对具有 xs:base64Binary 标准格式字符组成的节点进行优化,能够显著提高附件传输的效率,是目前最具有优势的附件传输方式。

分别在客户端和服务端实现 MTOM

客户端的 sendImage(HttpServletResponse) 方法读取本地 BMP 位图并将其发送到 Web 服务端,然后等待以获取服务端响应,并将结果显示在浏览器页面上。

要在客户端实现 MTOM,只需要在客户端代理类的 SOAPBinding 上调用 setMTOMEnabled(true) 方法,以启用 MTOM,具体代码见清单 6。


清单 6
                
// com.sample.client.Client.java
private void sendImage(HttpServletResponse response) throws Exception {
 SOAPBinding binding = (SOAPBinding)((BindingProvider)port).getBinding();
 binding.setMTOMEnabled(true);
 URL url = getServletContext().getResource("/ibm.bmp");
File file = new File(url.getFile());
FileInputStream is = new FileInputStream(file);
long length = file.length();
byte[] buf = new byte[(int) length];
is.read(buf, 0, (int) length);
Object obj = port.echo(buf);
response.getOutputStream().write((byte[]) obj);
}

要在 Web 服务端点实现 MTOM,只需要在服务实现类上添加 @BindingType 注释即可,如清单 7 所示。


清单 7
                
// com.sample.service.Echo.java
package com.sample.service;
import javax.jws.WebService;
@WebService()
@javax.xml.ws.BindingType(value=javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_MTOM_BINDING)
public class Echo {
public byte[] echo(byte[] bytes) {
 return bytes;
}
}

使用 TCP/IP Monitor 测试 Web 服务

TCP/IP Monitor 是 RAD 中内置的一个监控 TCP 报文传输的工具,它在客户端和服务器之间充当请求 / 响应代理的角色,因此可以记录所有经过的 TCP 报文。利用该工具可以方便地监控 Web 服务的请求 / 响应 SOAP 消息,包括消息的内容、大小以及服务响应时间等等。

要启用 Monitor,需要打开 RAD 的 Preferences 设置(图 8),选择 TCP/IP Monitor,点击 Add 添加如图 9 所示的 Monitor 定义,并启动该 Monitor。


图 8. RAD 的 Preferences 设置
RAD 的 Preferences 设置

图 9. 启动该 Monitor
启动该 Monitor

上述配置完成后,确保 TestWSEAR 应用已经正确发布到服务器并正在运行,然后在浏览器地址栏中输入http://localhost:9081/TestWSClient/Client,调用成功后,可以发现 Monitor 抓取到了请求和响应的 SOAP 报文。

图 10 是在启用 MTOM 前的测试结果:


图 10. 启用 MTOM 前的测试结果
启用 MTOM 前的测试结果

图 11 是在启用 MTOM 后的结果,与上述结果相比较,可以看到在请求和响应的头域中多了“application/xop+xml”的类型设置,消息体变成了 MIME 格式,消息的字节数也有较大幅度的减少,如果传输大文件,效果将更加明显。


图 11. 启用 MTOM 后的结果
启用 MTOM 后的结果




回页首


总结

JAX-WS 借助 Annotation 大幅度简化了 Web 服务的开发和部署,并且提供了支持异步调用的客户机编程模型和消息传输优化机制,使得 Web 服务的使用变得更为方便和灵活。IBM Rational Application Developer V7.0.0.3 提供了对开发、部署和测试 JAX-WS Web 服务的支持。本文说明了如何使用 RAD V7.0.0.3 构建 JAX-WS 客户端和服务端,并在这个过程中突出了 JAX-WS 的某些新特性。






回页首


下载

描述名字大小下载方法
本文示例源代码TestWSEAR.ear37KHTTP
关于下载方法的信息


参考资料

学习

获得产品和技术

讨论


关于作者

李凌,目前在 IBM 中国软件开发中心从事 WebSphere Application Server 解决方案开发工作,在 IMS SIP 领域有丰富的开发经验。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款