WebSphere Application Server V6.1 的 Web Services Feature Pack 中的 JAX-WS 客户端 API,第 1 部分: 创建 Dispatch 客户端

这个系列的文章向开发人员介绍 JAX-WS 2.0,它是受 WebSphere Application Server V6.1 的 Web Services Feature Pack 支持的新编程模型。第 1 部分逐步指导您如何使用各种 JAX-WS 客户端 API 创建 Dispatch 客户端。

Dan Sedov, 资深软件工程师, WSO2 Inc

Dan Sedov 的照片Dan Sedov 是 IBM Software Group 的资深软件工程师,负责 WebSphere Application Server 的 Web 服务组件的测试工作。在过去的两年中,Dan 是负责开发和测试第一个 Web Services Feature Pack 的 WebSphere 产品团队的成员。他创建和自动化 JAX-WS Web 服务引擎的测试。



Nikhil Thaker, 资深软件工程师, WSO2 Inc

Nikhil Thaker 的照片Nikhil Thaker 是 IBM Software Group 的资深软件工程师,是开发 Web Services Feature Pack 的 WebSphere 产品团队的成员。他在 Enterprise Application Integration 领域有超过 9 年的经验,并且最近两年关注 Web 服务。他作为 IBM Global Services 的 Enterprise Application Integration 领域的 IT 专家与各种 IBM 客户打过交道。他从事过的领域包括 Automotive、Health Care、电信和公共事业。



2010 年 2 月 01 日 (最初于 2007 年 7 月 18 日)

简介

WebSphere Application Server V6.1 Feature Pack for Web Services 扩展了 WebSphere Application Server V6.1 的功能,现在支持异步、可靠和安全地发送 Web 服务消息,并且以与其他供应商的互操作性为重点。Feature Pack 为新的 Web 服务标准提供支持,包括:

  • Web Services Reliable Messaging (WS-RM)
  • Web Services Addressing (WS-Addressing)
  • SOAP Message Transmission Optimization Mechanism (MTOM)
  • Web Services Secure Conversations (WS-SC)

它还支持以下基于标准的编程模型:

  • Java API for XML Web Services (JAX-WS 2.0)
  • Java Architecture for XML Binding (JAXB 2.0)
  • SOAP with Attachments API for Java (SAAJ 1.3)
  • Streaming API for XML (StAX 1.0)

在这个系列中,我们将关注 JAX-WS 2.0 客户端 API。

在 JAX-WS 中引入的新 Dispatch API 支持完全动态的服务调用。构建客户端不需要了解 WSDL 或 XML 文档,或者其他关于消息布局的知识。不过,这种灵活性要求开发人员必须非常熟悉 SOAP 协议和底层消息编写 API(比如 DOM 或 SAAJ)的细节。您可能需要使用 Dispatch 的场景的例子包括:

  • 文档交换场景,在该场景中 Dispatch 的动态性非常重要。例如,实际消息是外部过程的输出,比如来自外部系统的文件或 XSLT 转换的结果。在这种场景中,使用 Dispatch 来提供 SOAP 信封,以及发送消息并返回响应而不需与实际的消息交互。
  • 需要与更旧的、与 WS-I 不兼容的服务交互,比如与用 RPC 编码的服务交互。
  • 需要使用 JAXB 之外的数据绑定技术。JAX-WS 构建在它与 JAXB 2.0 的紧密集成之上。尽管没有针对 JAX-WS 中的其他绑定的直接支持,但在撰写本文时,我们看到许多适合使用另一种数据绑定技术的场景,比如 Castor 或 XML bean。
  • 未使用 SOAP 协议能够获得一些优势。Dispatch 支持 XML/HTTP 绑定,该绑定可用于调用基于应用程序定义的结构交换原始 XML 文档的端点。

本文提供:

  1. JAX-WS 概述
  2. 一个 JAX-WS Dispatch 客户端例子
  3. 几个用于处理 Web 服务消息的各种客户端 API 的例子

读者应该对 XML、SOAP、WSDL 和 Web 服务有良好的理解。


JAX-WS 2.0 概述

JAX-WS 2.0 是用于 Web 服务开发的新 Java API。它构建在旧的 JAX-RPC 编程模型之上,并且进行了许多改进。JAX-WS 2.0 的一些好处包括:

  • 区分数据绑定技术和支持 Java Architecture for XML Binding (JAXB) 2.0 的 Web 服务编程模型。
  • 支持 SOAP 1.2 和 SOAP 1.1。
  • 通过支持 WS-I Basic Profile 1.1 改善 Web 服务的互操作性。
  • 通过包含对在 JSR 181 中定义的注释(针对 Java 平台的 Web Services Metadata)和使用 JAX-WS 定义的注释的支持,添加没有描述器的 Web 服务部署。因为所有元数据都是标准化的注释,所以 Web 服务实现是独立于供应商的。
  • 支持异步客户端编程模型。
  • 简化处理程序的开发,并提供一个机制来允许处理程序与服务客户端和服务端点实现合作。
  • 包含 Java Platform, Extended Edition (Java EE) 5 和 Java 2 Plaform, Standard Edition (J2SE) 6 中的 API。

JAX-WS 2.0 客户端 API

图 1 显示了各种 JAX-WS 客户端 API 之间的类关系。JAX-WS 提供的这组 API 允许 Web 服务客户端调用部署在远程服务端点上的操作。您可以使用这些 API 以动态或静态、同步或异步的方式调用操作。

图 1. JAX-WS 客户端 API 的关系
图 1. JAX-WS 客户端 API 的关系

例子:创建 Dispatch 客户端

本文的剩余部分描述如何从 WSDL 文档创建 Dispatch 客户端,然后解释所使用的 API。这个例子使用以下 WSDL:

清单 1. WSDL 定义
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="HelloWorldService"
   xmlns="http://schemas.xmlsoap.org/wsdl/"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:tns="http://www.example.com/services/HelloWorld"
   xmlns:types="http://www.example.com/schemas/HelloWorld"
   targetNamespace="http://www.example.com/services/HelloWorld">

   <types>
      <schema
		xmlns="http://www.w3.org/2001/XMLSchema"
	 	targetNamespace=”http://www.example.com/schemas/HelloWorld”>

		<element name=”hello”>
			<complexType>
				<sequence>
					<element name=”message” type=”string” />
				</sequence>
			</complexType>
		</element>

		<element name=”helloResponse”>
			<complexType>
				<sequence>
					<element name=”message” type=”string” />
				</sequence>
			</complexType>
		</element>
	</schema>
   </types>

   <message name="HelloRequest">
      <part name="firstName" element="types:hello"/>
   </message>

   <message name="HelloResponse">
      <part name="greeting" element=”types:helloResponse"/>
   </message>

   <portType name="HelloWorldSEI">
      <operation name="hello">
         <input message="tns:HelloRequest"/>
         <output message="tns:HelloResponse"/>
      </operation>
   </portType>
   
   <binding name="HelloSoap11Binding" type="tns:HelloWorldSEI">
      <soap:binding
		style="document" 
		transport="http://schemas.xmlsoap.org/soap/http"/>
      <operation name="hello">
         <soap:operation soapAction="hello"/>
         <input>
            <soap:body use="literal"/>
         </input>
         <output>
            <soap:body use="literal"/>
         </output>
      </operation>
   </binding>

   <service name="HelloService">
      <port binding="tns:HelloSoap11Binding" name="HelloPort">
         <soap:address
             location="http://localhost:8080/hello/services/HelloService"/>
      </port>
   </service>
</definitions>

这个 WSDL 描述只有一个端口 HelloPort 的服务 HelloWorldService。portType HelloWorldSEI 定义一个 hello 操作。hello 操作使用封装的文档字面样式,因此发送 hello 请求时,将收到 helloResponse 响应。

让我们查看调用 hello 操作的简单 Dispatch 客户端。首先,我们查看整个调用,然后再查看细节部分:

清单 2. JAX-WS 客户端€“ javax.xml.ws.Dispatch 例子
// Qnames for service as defined in wsdl.
QName serviceName =
  new Qname("http://www.example.com/services/HelloWorld", "HelloService");

//QName for Port As defined in wsdl.
QName portName =
  new Qname("http://www.example.com/services/HelloWorld", "HelloPort");

//Endpoint Address
String  endpointAddress =
  "http://localhost:8080/hello/services/HelloService";

// Create a dynamic Service instance
Service service = Service.create(serviceName);

// Add a port to the Service
service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointAddress);

//Create a dispatch instance
Dispatch<SOAPMessage> dispatch = 
   service.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);

// Use Dispatch as BindingProvider
BindingProvider bp = (BindingProvider) dispatch;

// Optionally Configure RequestContext to send SOAPAction HTTP Header
Map<String, Object> rc = bp.getRequestContext();
rc.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
rc.put(BindingProvider.SOAPACTION_URI_PROPERTY, "hello");

// Obtain a preconfigured SAAJ MessageFactory
MessageFactory factory =
   ((SOAPBinding) bp.getBinding()).getMessageFactory();

// Create SOAPMessage Request
SOAPMessage request = factory.createMessage();

// Request Header
SOAPHeader header = request.getSOAPHeader();

// Request Body
SOAPBody body = request.getSOAPBody();

// Compose the soap:Body payload
QName payloadName =
   new QName("http://www.example.com/schemas/HelloWorld", "hello", "ns1");

SOAPBodyElement payload = body.addBodyElement(payloadName); 

SOAPElement message = payload.addChildElement("message");

message.addTextNode("Hello World!");

// Invoke the endpoint synchronously
SOAPMessage reply = null;

try {
	//Invoke Endpoint Operation and read response
	reply = dispatch.invoke(request);
} catch (WebServiceException wse){
	wse.printStackTrace();
}

// process the reply
body = reply.getSOAPBody();

QName responseName =
   new QName("http://www.example.com/schemas/HelloWorld", "helloResponse");

SOAPBodyElement bodyElement = body.getChildElements(responseName).next());
String message = bodyElement.getValue();

以上的例子通过下面的步骤使用 Dispatch API 调用一个端点上的操作:

  1. 创建和配置一个动态的 Service 实例
  2. 创建 Dispatch 客户端
  3. 配置请求上下文
  4. 编写请求消息
  5. 调用操作
  6. 处理响应消息

下面的几个小节分别讨论这些步骤。


步骤 1:创建和配置一个动态的 Service 实例

Service 类是一个表示 WSDL 服务的抽象。Service 实例可以是一个动态的服务(动态创建的服务)或一个静态的服务(由扩展服务类的 JAX-WS 工具生成的类)。在本文中,我将关注动态服务。

J2SE 客户端可以使用 Service.create() 方法来创建一个 Service 实例。当 J2SE 客户端选择创建一个 Service 实例时(如我们的例子所示),该实例就是一个动态 Service 实例,这表示它是动态配置的,而不是像生成的 Service Class 那样是静态配置的。可以通过两种方式创建动态的服务实例:

  • create(QName serviceName) 为带有给定名称的服务返回一个服务对象。没有向该服务附加任何 WSDL 文档。

    如清单 2 所示,我们首先像在 WSDL 中那样定义 Service QName,然后使用它来创建一个 Service

    清单 3. 创建动态的 Service 实例
    //Qnames for service
    QName serviceName =
      new Qname("http://www.example.com/services/HelloWorld", "HelloService");
    
    //Create a dynamic Service instance
    Service service = Service.create(serviceName);

    WSDL 服务是许多相关的端口的集合,每个端口都包含一个与特定协议绑定的端口类型,并且在特定的的端点地址上可用。如清单 2 所示,我们像 WSDL 描述的那样定义一个端口 QName,然后将该端口添加到 Service

    清单 4. 将端口添加到 Service
    QName portName =
      new Qname("http://www.example.com/services/HelloWorld", "HelloPort");
    
    //Endpoint Address
    String  endpointAddress =
      "http://localhost:8080/hello/services/HelloService";
    
    // Add a port to the Service
    service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointAddress);
  • create(URL wsdlLocation, QName serviceName) 为指定的 WSDL 文档返回服务对象并返回服务名,如清单 5 所示:
    清单 5. 使用 WSDL 创建动态服务
    //WSDL URL
    URL wsdlLocation = new URL("http://www.example.com/services/HelloWorld?wsdl");
    
    //Qname for service
    QName serviceName =
      new Qname("http://www.example.com/services/HelloWorld", "HelloService");
    
    //Create a dynamic Service instance
    Service service = Service.create(wsdlLocation, serviceName);

我们也可以选择使用静态的服务。当使用 JAX-WS 工具编译 WSDL 文件来生成 Java 工件时,静态服务就变得可用。我们在这里选择动态服务的原因是:

  • 我们不希望生成工件。
  • 在编写客户端时我们不知道将要调用的服务。例如,我们可能从中介获得 WSDL 文档,然后使用它动态地配置服务对象。
  • 我们仅使用 Dispatch 来发送在另一个系统中生成的消息。

步骤 2:创建 Dispatch 客户端

Dispatch 是一个低级的 API,它需要客户端使用基于 XML 的技术构造消息或消息负载。更高级的 JAX-WS API 隐藏了处理 XML 的细节,并允许用户使用更加熟悉的 Java 对象。Dispatch 支持两种由常量标识的使用模式:

  • javax.xml.ws.Service.Mode.PAYLOAD
  • javax.xml.ws.Service.Mode.MESSAGE

PAYLOAD 模式中,客户端应用程序仅处理 <soap:Body> 元素的内容(消息负载),而不是整个消息。如果服务使用 SOAP 绑定,JAX-WS 运行时负责提供 SOAP 信封。

清单 6. 在 PAYLOAD 模式下创建 Dispatch 实例
//Create a dispatch instance
Dispatch<SOAPMessage> dispatch = 
   service.createDispatch(portName, javax.xml.transform.Source.class,
Service.Mode.PAYLOAD);

MESSAGE 模式下,客户端应用程序直接处理特定于协议的消息结构。客户端负责提供 SOAP 信封和消息负载。在我们的例子中,我们使用 MESSAGE 模式,如清单 7 所示。

清单 7. 在 MESSAGE 模式下创建 Dispatch 实例
//Create a dispatch instance
Dispatch<SOAPMessage> dispatch = 
   service.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);

步骤 3:配置请求上下文

JAX-WS 客户端 API 实现 BindingProvider 接口,这允许它们在端点上为消息交换的请求和响应阶段维护独立的上下文。请求和响应上下文的类型为 Map<String, Object>, 并且使用 BindingProvider 接口的 getRequestContextgetResponseContext 方法获取。

下表显示了在创建了 Dispatch 实例之后可以在请求上下文上设置的标准属性:

属性作用
javax.xml.ws.service.endpoint.address 作为特定于协议的 URI 的服务端点的地址。URI 的模式必须与正在使用的协议绑定匹配。
javax.xml.ws.security.auth.usernamejavax.xml.ws.security.auth.password 用于 HTTP 基本身份验证的用户名和密码。
javax.xml.ws.session.maintain 表示客户端希望加入 HTTP 会话。
javax.xml.ws.soap.http.soapaction.usejavax.xml.ws.soap.http.soapaction.uri 控制是否通过 HTTP 请求在 SOAP 中使用 SOAPAction HTTP 头部。
清单 8. 使用绑定提供者设置 RequestContext
//get Binding provider
BindingProvider bp = (BindingProvider) dispatch;

// Configure RequestContext (optional step)
Map<String, Object> rc = bp.getRequestContext();

//Ask RequestContext to USE SOAPAction.
rc.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);

//Add SOAPAction to RequestContext
rc.put(BindingProvider.SOAPACTION_URI_PROPERTY, "hello");

步骤 4:编写请求消息

我们的例子使用类型为 SOAPMessage 的 Dispatch,但 Dispatch 在编写消息方面还支持几种其他 API。例如,带有 DOMSourcejavax.xml.transform.SourceSAXSourceStreamSource 子接口、JAXB 2.0 对象和 javax.activation.DataSource 都是有效的 Dispatch 类型。我们的例子通过使用 SAAJ SOAPMessage API 编写消息来演示调用,如清单 9 所示:

清单 9. 创建 SOAP 消息
//Create SOAPMessage Request
SOAPMessage request = factory.createMessage();

//Request Header
SOAPHeader header = request.getSOAPHeader();

//Request Body
SOAPBody body = request.getSOAPBody();

从这里可以看到,payloadName 是 XML Schema “hello” 元素的 QName。

清单 10. 表示操作签名的 wsdl 元素
 <schema
	xmlns="http://www.w3.org/2001/XMLSchema"
	targetNamespace="http://www.example.com/schemas/HelloWorld">

	<element name="hello">
		<complexType>
			<sequence>
				<element name="message" type="string" />
			</sequence>
		</complexType>
	</element>
</schema>

// Compose the soap:Body payload
QName payloadName =
   new QName("http://www.example.com/schemas/HelloWorld", "hello", "ns1");

SOAPBodyElement payload = body.addBodyElement(payloadName);
SOAPElement message = payload.addChildElement("message");
message.addTextNode("Hello World!");

您可能很想知道为什么要这样构造消息。我们的简单的 WSDL 使用文档样式的 SOAP 绑定,如清单 11 所示:

清单 11. 文档样式的 SOAP 绑定
<soap:binding
		style="document" 
		transport="http://schemas.xmlsoap.org/soap/http"/>

在这种样式中,我们发送 XML 文档。其他样式发送不同格式的消息。developerWorks 文章 Which style of WSDL should I use? 描述了不同的 WSDL 样式及其对应的消息。


步骤 5:调用操作

在创建了请求之后,将使用 Dispatch 实例上的几个 Invoke 方法之一分发它。我们的例子使用同步请求-响应消息交换模式,如清单 12 所示:

清单 12. 分发带有请求的调用操作
try {
	//Invoke Endpoint Operation and read response
	reply = dispatch.invoke(request);
} catch (WebServiceException wse){
	wse.printStackTrace();
}

如果未能成功分发请求,将抛出一个 WebServiceException,并且其原因是一个底层的异常(例如,HostNotFoundException)。如果端点在处理请求时出现问题,将抛出 SOAPFaultException


步骤 6:处理响应消息

从这个 Invoke 收到的响应最终被处理,即提取回复 SOAP 消息的主体并根据 WSDL 定义解析它。在这个例子中,我们希望接收到 helloResponse XML 元素,如清单 13 所示:

清单 13. 响应处理
<element name="helloResponse">
	<complexType>
		<sequence>
			<element name="message" type="string" />
		</sequence>
	</complexType>
</element>

// process the reply
body = reply.getSOAPBody();

QName responseName =
   new QName("http://www.example.com/schemas/HelloWorld", "helloResponse");

SOAPBodyElement bodyElement = body.getChildElements(responseName).next());
String message = bodyElement.getValue();

结束语

在本文中,我们学习了如何创建一个可用于动态地调用 Web 服务的 Dispatch 客户端。您还简单了解了其他一些 JAX-WS 客户端 API,它们可用于配置发送到服务器的 SOAP 消息的上下文。Dispatch API 的 WebSphere Application Server V6.1 Web Services Feature Pack 实现支持 javax.xml.transform.Source、JAXB Object、javax.xml.soap.SoapMessage 和 java.lang.String 类型的输入和输出消息类型。Web 服务客户端可以使用这个 Dispatch API 调用由 Web 服务端点实现的单向或双向的同步和异步操作。您可能需要使用 Dispatch API 调用 Web 服务的其他一些场景包括:

  • 需要与遗留的 JAX-RPC 或不遵从 WS-I 的 Web 服务进行互操作时。
  • 使用 xml/http 绑定而不是传统的 SOAP 绑定调用 Web 服务时。
  • 使用数据绑定而不是 JAXB 调用 Web 服务时。

下载

描述名字大小
项目交换文件jaxwsDispatch.zip124KB
项目交换文件jaxwsProxy_samples.zip158KB

参考资料

学习

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=WebSphere, SOA and web services
ArticleID=465877
ArticleTitle=WebSphere Application Server V6.1 的 Web Services Feature Pack 中的 JAX-WS 客户端 API,第 1 部分: 创建 Dispatch 客户端
publish-date=02012010