利用 WAS 6.1 WebService 功能部件包开发 JAX-WS 2.0 Web services

引言

JAX-WS 2.0 的全称为 Java API for XML-Based Web services (JAX-WS) 2.0。JAX-WS 2.0 是对 JAX-RPC 1.0 规范的扩展,是 JAX-RPC 1.1 的后续版本, JAX-RPC 2.0 标准发布不久后便被重新命名为 JAX-WS 2.0。 JAX-WS 2.0 是面向 Java 5 的开发 Web services 的最新编程标准,它提供了新的编程模型和对以往的 JAX-RPC 方式的 Web services 进行了增强。在 WebSphere 应用服务器 6.1 Web services 功能部件包中提供了对 JAX-WS 2.0 的支持。本文结合 WebSphere 里的开发工具 AST(Application Server Toolkit) 讲述了 JAX-WS 2.0 标准下 Web services 的开发过程,同时介绍了 JAX-WS 2.0 一些重要的 API 和命令行工具 wsimport,wsgen 的使用。本文对于想了解 Web services 最新变化和准备采用 JAX-WS 2.0 编程的相关人员有一定的帮助。

 




回页首


JAX-WS 2.0 介绍

和以往的 JAX-RPC 相比,JAX-WS 2.0 的主要特点有:

  • 新的 API 和新的编程模型。新的 API 主要包含在 javax.xml.ws 包中,包括 service 端和 client 端的一些核心类。新的编程模型包括增强的 Handler Framework,异步调用和 Provider/Dispatch 动态编程模型。
  • 采用 annotations 来描述 Web services,不再依赖部署以往的 Web service 描述文件。
  • 通过 JAXB 2.0 完成 xml data 和 Java 对象的绑定,改变了 JAX-RPC 1.0 里同时存在两套 binding 机制的不便。
  • MTOM/XOP(SOAP Message Transmission Optimization Mechanism/XML Binary Optimized) 和 swaRef(SOAP Attachment Refenreces),解决了在 SOAP 消息里传输二进制附件的问题,同时对消息传输进行了优化。
  • 对 SOAP 1.2 的支持。
  • 针对上述特点,Web services 功能部件包主要在以下几个方面提供了相应的支持:
  • 在 WAS(WebSphere Application Server) runtime 中增加了对 JAX-WS 2.0 的支持 , 使得基于 JAX-WS 2.0 的 Web services 能在 WAS 中部署运行。
  • 新增了用于创建 JAX-WS 2.0 应用的一些命令行工具,如 wsimport 和 wsgen。
  • 在 AST 中增加了开发 JAX-WS 2.0 应用的插件。

此外,功能部件包同时提供了对其它如 JAXB_2.0, MTOM/XOP API 以及基于 PolicySet 安全化 Web services 等高级特性的支持。

 




回页首


JAX-WS 2.0 开发过程

同 基于 JAX-RPC 的 Web services 一样,JAX-WS 2.0 的开发分为 service 端和 client 端。在 service 端,可以选择自顶向下或自底向上的方式来创建 Web services,这两种方式可以通过 AST 或命令行工具来完成。在 client 端,一般通过 AST 或命令行工具根据 WSDL 文件创建用于调用 Web services 的辅助类,然后再在自己的代码中使用这些辅助类。 JAX-WS 2.0 提供了多种 client 端的编程模型。下面将分别介绍 service 端和 client 端的开发过程。

Service 端的开发

JAX-WS 2.0 有两种开发过程 : 自顶向下和自底向上。自顶向下方式指通过一个 WSDL 文件来创建 Web services,自底向上是从 Java 类出发创建 Web services。两种开发过程最终形成的文件包括:

  • SEI(service endpoint interface)。一个 SEI 对应 WSDL 中 Web service 的一个 port,在 Java 中是一个 Java 接口。
  • SEI 实现类。
  • WSDL 和 xsd 文件。

Web services 既可以包含在一个 web module 中发布,也可以包含在 EJB module 中发布。下面我们结合实例来看一个自顶向下的 Web services 的开发过程。该例子包含的 Web services 很简单:一个 service,该 service 只有一个 port,该 port 只有一个操作 addNumber。

首先,我们开发一个普通的 Java Bean。在 AST 中创建两个项目:一个动态 web 项目,包含我们示例的 Web services;另一个 J2EE 项目,用于生成 ear。

清单 1. 用于创建 Web service 的一个普通 Java Bean

package com.ibm.ws.demo.server;

public class SimpleBean {
public int addNumber(int i , int j) {
return i + j;
}
}

 

在 AST 工具中,选中该类,在右键弹出菜单中,启动 Web service 创建向导。在向导中,您需要选择 Web services 运行时的 runtime 为 IBM WebSphere JAX-WS。同时,选择生成 WSDL 文件。其余步骤按缺省设置。

最后生成的项目结构如下:


上 图中,SimpleBeanDelegate.java, AddNumber.java 和 AddNumberResponse.java 为向导生成的 java 类,WebContent 下还生成了两个 Web service 的描述文件 SimpleBeanService.wsdl 和 SimpleBeanService_schema1.xsd。

在 AST 中导出 ear 文件,在 WebSphere 管理控制台上部署,再启动应用。在浏览器中通过下面形式的 URL 可以验证 Web services 是否成功启动。

http://hostname:port/webmodule/QName

注意 AST 中自动生成的一个代理类 SimpleBeanDelegate.java:

清单 2. 用于部署 Web service 的代理类 SimpleBeanDelegate.java

import javax.jws.WebService;
import javax.xml.ws.BindingType;
import javax.jws.soap.SOAPBinding;

@WebService (targetNamespace="http://server.demo.ws.ibm.com/",
serviceName="SimpleBeanService",
portName="SimpleBeanPort",
WSDLLocation="WEB-INF/WSDL/SimpleBeanService.WSDL")
public class SimpleBeanDelegate{

SimpleBean _simpleBean = new SimpleBean();

public int addNumber(int i, int j) {
return _simpleBean.addNumber(i,j);
}

}

 

上面这个类是真正用于部署 Web services 的类,该类采用了 Annotation 来描述 Web services。 Annotation 是 Java 5 的一大语言特性,采用 Annotation 描述 Web services 的元数据,减轻了开发者的部署负担。在 javax.jws 包中定义了如下主要的 Annotation:

  • javax.jws.WebService
  • javax.jws.WebMethod
  • javax.jws.WebParam

Client 端的开发

客 户端开发的通常过程是从已有的 WSDL 出发,创建辅助类 JAXB 对象和 service 代理类,然后基于这些类开发自己的客户端应用。在 AST 中,选中工程 SimpleJaxWS 下的 WSDL 文件 SimpleBeanService.WSDL,在右键菜单中启动 Web services 客户端创建向导。在创建过程中,同样需要选择 runtime 为 IBM WebSphere JAX-WS, 其它按默认设置。最终生成的客户端项目结构如下:


其 中自动生成的 Java source 包括 JAXB 对象 , 如上图中的 AddNumber.java,AddNumberResponse.java, ObjectFactory.java 以及 package-info.java 类,和 service 代理类,如上图中的 SimpleBeanDelegate.java, SimpleBeanPortProxy.java 以及 SimpleBeanService.java 类。然后,再写一个测试类 WSClient.java,该类是一个独立运行的 Java application。测试时,您需要在 classpath 中添加一个 thin client:com.ibm.jaxws.thinclient_6.1.0.jar。该 jar 在 $WAS_HOME/runtimes 目录下可以找到。

清单 3. 调用 Web service 的客户端 WSClient.java

public class WSClient {

QName serviceName = new QName("http://server.demo.ws.ibm.com/",
"SimpleBeanService");
QName portName = new QName("http://server.demo.ws.ibm.com/",
"SimpleBeanPort");

String host = "9.186.117.142" ;
String port = "9080" ;

String endpt ;
String WSDLURL ;
SimpleBeanService service = null;


public WSClient() {

endpt = "http://"+ host +":" + port +"/SimpleJaxWS/SimpleBeanService" ;
WSDLURL = "http://"+ host +":" + port
+ "/SimpleJaxWS/SimpleBeanService/WEB-INF/WSDL/SimpleBeanService.WSDL" ;
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|

}

/**
* Get the SEI from endpoint address
* @param endpt
* @return
*/
public SimpleBeanDelegate getSEIFromEndpoint() {

SimpleBeanDelegate port = null ;
BindingProvider p = null;

try {
service = new SimpleBeanService(null, serviceName);
System.out.println("Looking up service "
+ service.getServiceName());

port = service.getSimpleBeanPort();
p = (BindingProvider) port;
p.getRequestContext().put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpt);
//p.getRequestContext().put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
//p.getRequestContext().put(BindingProvider.SOAPACTION_URI_PROPERTY, "invoke");
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|


} catch (Exception e) {
e.printStackTrace() ;
}
return port ;

}



public void simpleCall() {

try {

SimpleBeanDelegate port = getSEIFromEndpoint() ;
System.out.println(port.addNumber(8, 9));

} catch (Exception e) {
e.printStackTrace();
}
}


public static void main(String[] args) {

WSClient client = new WSClient() ;
client.simpleCall() ;


}

 

客户端调用 Web service 的常见过程为:先创建一个 service 对象,再从 service 对象获得 SEI,最后调用 SEI 的方法去访问 Web service。

Web services 客户端的异步调用方式

除 了上述的同步调用方式外,JAX-WS 2.0 还提供了异步调用,采用异步调用,客户端不需要等待 SOAP response 消息的返回,就可以继续别的处理。异步调用方式有 polling 和 callback 两种,这里只讲 callback 方式。 callback 就是提供一个 callback 函数,供消息返回时调用。在 Java 中,该 callback 函数是一个实现了特定接口的类。如果要异步方式访问 Web services,首先得在 SEI 中生成一个异步调用的方法。在用 AST 中的 Web services 向导工具创建 Web services 客户端时,注意选中“生成异步调用方法”:

生成的异步调用方法如下:

清单 4. 用于异步调用 Web service 的方法定义

@WebMethod(operationName = "addNumber")
@RequestWrapper(localName = "addNumber",
targetNamespace = "http://server.demo.ws.ibm.com/",
className = "com.ibm.ws.demo.client.AddNumber")
@ResponseWrapper(localName = "addNumberResponse",
targetNamespace = "http://server.demo.ws.ibm.com/",
className = "com.ibm.ws.demo.client.AddNumberResponse")
public Future < ? > addNumberAsync(
@WebParam(name = "arg0", targetNamespace = "")
int arg0,
@WebParam(name = "arg1", targetNamespace = "")
int arg1,
@WebParam(name = "asyncHandler", targetNamespace = "")
AsyncHandler < AddNumberResponse > asyncHandler);

 

当 SOAP response 返回时,客户端 runtime 会调用我们提供的 AsyncHandler。下面是一个实现了 AsyncHandler 的类。

清单 5. 用于异步调用 Web service 的 Handler 类,处理返回的 SOAP 消息

import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Response;

public class CallbackHandler implements AsyncHandler <AddNumberResponse>{

public void handleResponse(Response response) {

AddNumberResponse res = (AddNumberResponse)response ;
//do something with the response...
System.out.println("Response result is : " + res.getReturn());
}
}

 

最终,客户端异步调用 Web services 的形式为:

清单 6. 异步调用 Web service 的代码

public void asyncCall() {

try {

SimpleBeanDelegate port = getFromJavaBeanImpl(endpt) ;
CallbackHandler asyncHandler = new CallbackHandler() ;
port.addNumberAsync(8, 9, asyncHandler) ;

//do other things...

} catch (Exception e) {
e.printStackTrace();
}
}

 

Provider/Dispatch 编程模型

JAX-WS 2.0 还提供了 service 端和 client 端的动态编程模型:Provider/Dispatch 模型。Provider<T> 和 Dispatch<T> 分别是 service 端和 client 端提供的两个接口,该编程模型可以让您在 xml message 级别上工作。换言之,您可以通过编程操纵整个 SOAP 信封或 SOAP 信封的 body。 T 的类型和另一个参数 Service.Mode 组合在一起,决定了操作的 xml message 到底是整个 SOAP 信封还是部分。T 的两种类型为 Source 和 SOAPMessage,两种 Service 模式为 Service.Mode.MESSAGE 和 Service.Mode.PAYLOAD。下面给出了其中一种组合的示例。

Service 端的代码示例

清单 7. 以 Provider 模式实现 Web service 的 service 端 Java 类

@WebServiceProvider 
@ServiceMode(value=Service.Mode.MESSAGE)
public class ProviderImpl implements
Provider<SOAPMessage> {
public SOAPMessage invoke(SOAPMessage msg) {
//here the msg is the entire SOAP request
// do request processing
SOAPMessage response = ...;
return response;
}
}

 

Client 端的代码示例

清单 8. 以 Dispatch 模式调用 Web service 的 client 端 Java 类

//create the service
Service service = Service.createService(QName serviceQName);
//or Service service = Service.createService(URL WSDLLocation, QName serviceQName);
//set the binding
service.addPort(QName portName, String SOAPBinding.SOAP11HTTP_BINDING,
String endpointAddress);
//create the dispatch
Dispatch dispatch = service.createDispatch(QName portName, Class clazz,
Service.Mode mode);
//Dispatch dispatch = service.createDispatch(QName portName, JAXBContext jaxbcontext,
Service.Mode mode);

//invoke the Web services
Object response = dispatch.invoke(T);
dispatch.invokeOneway(T);
//or Response<T> response = dispatch.invokeAsync(T);
//or Future<?> response = dispatch.invokeAsync(T, AsyncHandler);

 

这里的问题是如何生成类型 T 的实例,答案是通过 JAXB 标准提供的 API 将 Java object 转化为 xml message 对象。

 




回页首


通过 wsgen,wsimport 工具创建 Web services

除 了 AST 中提供的图形界面开发方式外,Web services 功能部件包还提供了创建 Web services 的命令行工具。其中,wsgen 支持从 Java class 创建 Web services,wsimport 支持从 WSDL 创建 Web services。分别对应于 JAX-RPC 方式下的 Java2WSDL 和 WSDL2Java。

清单 9. wsgen 命令格式

wsgen [options] < SEI >

主要选项:

  • -d 指定生成的 class 文件的位置。
  • -s 指定生成的 Java source 文件的位置。
  • -r 指定生成的 resources 文件的位置。如 WSDL,xsd 的位置。
  • -WSDL,-servicename,-portname 三个参数指定生成的 WSDL 文件中的 service 和 port 的名称。

注 意:这里的 SEI 是一个 endpoint implementation class,而不是一个接口。你必须先写好一个 endpoint 的实现类,如上面的 SimpleBeanDelegate,该类中用 @WebService 声明好 Web service,再将它编译成 class 文件,才能提供给 wsgen 使用。

清单 10. wsgen 使用实例

wsgen.sh -cp classes -s src -d bin -r web -WSDL com.ibm.ws.demo.server.SimpleBeanDelegate

 

清单 11. wsimport 命令格式

wsimport [options] <WSDL_URI>

主要选项:

  • -d 指定生成的 class 文件的位置。
  • -s 指定生成的 Java source 文件的位置。
  • -WSDLlocation 指定生成的 Java source 中 @WebService.WSDLLocation 和 @WebServiceClient.WSDLLocation 的值。

清单 12. wsimport 使用实例

wsimport.sh -d classes -s src -WSDLlocation /WEB-INF/WSDL/SimpleBeanService.WSDL 
SimpleBeanService.WSDL





回页首


通过 Ant task 自动构建 Web services 应用

WebSphere 同时提供了用于创建 Web services 的 ant task,这些 task 的参数和 wsgen,wsimport 是一致的。利用这些 ant task,您可以在大型项目中完成自动构建工作。

清单 13. 在 Ant 中使用 wsgen 和 wsimport

<wsgen sei="..."
destdir="directory for generated class files"
classpath="classpath"
resourcedestdir="directory for generated resource files such as WSDLs"
sourcedestdir="directory for generated source files"
keep="true|false" verbose="true|false"
genWSDL="true|false" protocol="soap1.1|soap1.2"
servicename="..."
portname="..."
extension="true|false">
<classpath refid="..."/>
</wsgen>

<wsimport WSDL="..."
destdir="directory for generated class files"
sourcedestdir="directory for generated source files"
keep="true|false" extension="true|false"
verbose="true|false" version="true|false"
WSDLLocation="..."
catalog="catalog file"
package="package name">
<binding dir="..." includes="..." />

</wsimport>

 

结束语

本 文向您讲述了 JAX-WS 2.0 的主要特性,并通过示例展示了 Web services 新的编程模型和 API 及其开发过程。通过本文,您可以对 JAX-WS 2.0 有一个初步的了解,并懂得如何通过 WebSphere 提供的工具开发简单的符合 JAX-WS 2.0 的 Web services。值得说明的是,本文并没有向您介绍 JAX-WS 2.0 的全部特性,您可以通过本文提供的参考资源获得更多信息。



参考资料

学习


获得产品和技术


讨论
参与 developerWorks Blog ,从而加入到 developerWorks 社区中来,其中包括以下与 SOA 和 Web 服务相关的 Blogs:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值