第 41 章 使用 Raw XML 消息

摘要

高级别 JAX-WS API,通过将数据编入 JAXB 对象,从而使开发人员使用原生 XML 消息影响。但是,在有些情况下,最好直接访问原始 XML 消息数据,这些数据在线上传递。JAX-WS API 提供了两个接口,它们提供对原始 XML 的访问: Dispatch 接口是客户端接口,Provider 接口是服务器端接口。

41.1. 在消费者中使用 XML

摘要

Dispatch 接口是一个低级 JAX-WS API,可让您直接使用原始消息。它接受并返回消息或有效负载,这是许多类型,包括 DOM 对象、SOAP 消息和 JAXB 对象。由于它是低级 API,所以 Dispatch 接口不会执行任何消息准备,因为该消息准备了更高级别的 JAX-WS API 执行。您必须确保正确构建消息或有效负载,传递给 Dispatch 对象,并对被调用的远程操作有意义。

41.1.1. 使用模式

概述

分配对象有两种 使用模式

您为 Dispatch 对象指定的使用模式决定了传递给用户级别的代码的详细信息量。

消息模式

在消息模式中,Dispatch 对象用于完整消息。完整消息中包含任何绑定特定标头和打包程序。例如,与需要 SOAP 消息的服务交互的用户必须提供完全指定的 SOAP 消息的 call () 方法。调用() 方法也返回完全指定的 SOAP 消息。消费者代码负责完成并读取 SOAP 消息的标头和 SOAP 消息的信封信息。

在使用 JAXB 对象时,消息模式不是理想的选择。

指定 Dispatch 对象使用消息模式在创建 Dispatch 对象时提供值 java.xml.ws.Service.Mode.MESSAGE。有关创建 Dispatch 对象的更多信息,请参阅 “创建 Dispatch 对象”一节

有效负载模式

有效负载模式 中,也称为消息有效负载模式,Dispatch 对象仅适用于消息的有效负载。例如,在有效负载模式下工作的 Dispatch 对象只适用于 SOAP 消息的正文。绑定层处理任何绑定级别的打包程序和标头。当从 call () 方法返回的结果时,绑定级别打包程序和标头已经分条,并且仅保留消息正文。

在使用不使用特殊打包程序的绑定时,如 Apache CXF XML 绑定、有效负载模式和消息模式提供相同的结果。

指定 Dispatch 对象使用有效负载模式,在创建 Dispatch 对象时提供 java.xml.ws.Service.Mode.PAYLOAD 的值。有关创建 Dispatch 对象的更多信息,请参阅 “创建 Dispatch 对象”一节

41.1.2. 数据类型

概述

因为 Dispatch 对象是低级对象,所以无法使用与更高级别消费者 API 相同的 JAXB 生成的类型进行优化。将对象与以下对象类型的分配:

使用 Source 对象

Dispatch 对象接受并返回来自 javax.xml.transform.Source 接口的对象。源对象受任何绑定支持,在消息模式或有效负载模式中支持。

源对象是包含 XML 文档的低级别对象。每个 Source 实施都提供了访问存储 XML 文档的方法,然后操作其内容。以下对象实现 Source 接口:

DOMSource
将 XML 消息作为文档对象模型(DOM)树保存.XML 消息作为一组节点对象存储,它们通过 get Node () 方法进行访问。可以使用 setNode () 方法更新或添加到 DOM 树中。
SAXSource
将 XML 消息保存为 XML (SAX)对象的简单 API。SAX 对象包含一个 InputSource 对象,该对象保存原始数据和解析原始数据的 XMLReader 对象。
StreamSource
将 XML 消息作为数据流保存。数据流可以与任何其他数据流相同。

如果您创建 Dispatch 对象使其使用通用源对象,Apache CXF 会将消息返回为 SAXSource 对象。

可以使用端点 的源-preferred-format 属性更改此行为。有关配置 Apache CXF 运行时的信息,请参阅 第 IV 部分 “配置 Web 服务端点”

使用 SOAPMessage 对象

当以下条件满足时,分配对象可以使用 javax.xml.soap.SOAPMessage 对象:

  • Dispatch 对象使用 SOAP 绑定
  • Dispatch 对象使用消息模式

SOAPMessage 对象保存 SOAP 消息。它们包含一个 SOAPPart 对象和零个或更多 AttachmentPart 对象。SOAPPart 对象包含 SOAP 消息的特定部分,包括 SOAP envelope、任何 SOAP 标头和 SOAP 消息正文。AttachmentPart 对象包含作为附件传递的二进制数据。

使用 DataSource 对象

当以下条件满足时,分配对象可以使用实现 javax.activation.DataSource 接口的对象:

  • Dispatch 对象使用 HTTP 绑定
  • Dispatch 对象使用消息模式

Datasource 对象提供了一种机制,可用于处理来自各种来源的 MIME 类型数据,包括 URL、文件和字节阵列。

使用 JAXB 对象

虽然 Dispatch 对象是低级 API,但允许您处理原始消息,它们也允许您处理 JAXB 对象。要使用 JAXB 对象,必须传递一个 JAXBContext,以便可使用的 JAXBContext 和 unmarshal the JAXB 对象。创建 Dispatch 对象时会传递 JAXBContext

您可以将任何 JAXBContext 对象理解为 调用()方法的参数。您还可以将返回的消息转换为 JAXBContext 对象所理解的任何 JAXB 对象。

有关创建 JAXBContext 对象的详情,请参考 第 39 章 使用 A JAXBContext 对象

41.1.3. 使用 Dispatch 对象

流程

要使用 Dispatch 对象来调用远程服务,应遵循以下顺序:

  1. 创建 Dispatch 对象。
  2. 构建 请求消息。
  3. 调用正确的 calls () 方法。
  4. 解析响应消息。

创建 Dispatch 对象

要创建 Dispatch 对象,请执行以下操作:

  1. 创建一个 Service 对象来代表 wsdl:service 元素,用于定义 Dispatch 对象要进行调用的服务。请参阅 第 25.2 节 “创建服务对象”
  2. 使用 Service 对象的 createDispatch () 方法创建 Dispatch 对象,如 例 41.1 “createDispatch () 方法” 所示。

    例 41.1. createDispatch () 方法

    publicDispatch<T&gt;createDispatchQNameportNamejava.lang.Class<T&gt;typeService.ModemodeWebServiceException

    注意

    如果您使用 JAXB 对象了 createDispatch () 的方法签名:publicDispatch<T&gt;createDispatchQNameportNamejavax.xml.bind.JAXBContextcontextService.ModemodeWebServiceException

    表 41.1 “Parameters for createDispatch() 描述 createDispatch () 方法的参数。

    表 41.1. Parameters for createDispatch()

    参数描述

    portName

    指定 wsdl:port 元素的 QName,它代表 Dispatch 对象进行调用的服务提供商。

    type

    指定 Dispatch 对象使用的对象的数据类型。请参阅 第 41.1.2 节 “数据类型”。在使用 JAXB 对象时,此参数指定用于 marshal 和 unmarshal JAXB 对象的 JAXBContext 对象。

    模式

    指定 Dispatch 对象的使用模式。请参阅 第 41.1.1 节 “使用模式”

例 41.2 “创建 Dispatch 对象” 显示创建在有效负载模式中与 DOMSource 对象一同创建的 Dispatch 对象的代码。

例 41.2. 创建 Dispatch 对象

package com.fusesource.demo;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;

public class Client
{
public static void main(String args[])
  {
    QName serviceName = new QName("http://org.apache.cxf", "stockQuoteReporter");
    Service s = Service.create(serviceName);

    QName portName = new QName("http://org.apache.cxf", "stockQuoteReporterPort");
    Dispatch<DOMSource> dispatch = s.createDispatch(portName,
                                                  DOMSource.class,
                                                  Service.Mode.PAYLOAD);
    ...

构建请求消息

在使用 Dispatch 对象时,必须从头开始构建请求。开发人员负责确保传递到 Dispatch 对象的消息与目标服务提供商可以处理的请求匹配。这需要准确了解服务提供商使用的信息以及需要的任何标头信息。

这些信息可以由 WSDL 文档或定义消息的 XML Schema 文档提供。虽然服务提供商大有不同,但要遵循以下几个指南:

  • 请求的 root 元素基于与正在调用 的操作 对应的 wsdl:operation 元素的值。

    警告

    如果被调用的服务使用 doc/literal bare 消息,则请求的 root 元素基于 wsdl:part 元素的 name 属性的值。

  • 请求的根元素是命名空间合格的。
  • 如果被调用的服务使用 rpc/literal 消息,则请求中的顶层元素将不是命名空间合格的元素。

    重要

    顶级元素的子项可能是命名空间合格的。要保持某些情况,您必须检查其 schema 定义。

  • 如果被调用的服务使用 rpc/literal 消息,则顶级元素都为空。
  • 如果被调用的服务使用 doc/literal 消息,则消息的 schema 定义决定任何元素是否满足命名空间。

如需有关服务如何使用 XML 消息的更多信息,请参阅 WS-I 基本配置集

同步调用

对于生成响应的用户进行同步调用,请使用 例 41.3 “Dispatch.invoke () 方法” 中显示的 Dispatch 对象的 call () 方法。

例 41.3. Dispatch.invoke () 方法

TinvokeTmsgWebServiceException

响应的类型和传递给 call () 方法的请求都会被确定何时创建 Dispatch 对象。例如,如果您使用 createDispatch (portName、SOAPMessage.class、Service.Mode.MESSAGE) 创建 Dispatch 对象,则响应和请求都是 SOAPMessage 对象。

注意

在使用 JAXB 对象时,响应和请求都可以是提供的 JAXBContext 对象的任何类型。另外,响应和请求可以是不同的 JAXB 对象。

例 41.4 “使用 Dispatch 对象进行同步调用” 显示使用 DOMSource 对象在远程服务上进行同步调用的代码。

例 41.4. 使用 Dispatch 对象进行同步调用

// Creating a DOMSource Object for the request
DocumentBuilder db = DocumentBuilderFactory.newDocumentBuilder();
Document requestDoc = db.newDocument();
Element root = requestDoc.createElementNS("http://org.apache.cxf/stockExample",
                                          "getStockPrice");
root.setNodeValue("DOW");
DOMSource request = new DOMSource(requestDoc);

// Dispatch disp created previously
DOMSource response = disp.invoke(request);

异步调用

分配对象也支持异步调用。与 第 40 章 开发异步应用程序 中讨论的更高级别异步 API 一样,Dispatch 对象既可以使用轮询方法和回调方法。

使用轮询方法时,calls Async () 方法返回 Response<t& gt; 对象,该对象可以被轮询以查看响应是否已到达。例 41.5 “Dispatch.invokeAsync () 方法进行轮询” 显示用于使用轮询方法进行异步调用的方法的签名。

例 41.5. Dispatch.invokeAsync () 方法进行轮询

response <T&gt;invokeAsyncTmsgWebServiceException

有关使用轮询方法进行异步调用的详情,请参考 第 40.4 节 “使用轮询方法实施同步客户端”

使用回调方法时,calls Async () 方法采用 AsyncHandler 实施,该实施可在返回时处理响应。例 41.6 “使用回调的 Dispatch.invokeAsync () 方法” 显示用于利用回调方法进行异步调用的方法的签名。

例 41.6. 使用回调的 Dispatch.invokeAsync () 方法

future<?&gt; 调用AsyncTmsgAsyncHandler<T&gt;handlerWebServiceException

有关使用回调方法进行异步调用的详情,请参考 第 40.5 节 “使用回调方法实施同步客户端”

注意

与同步 调用() 方法一样,当您创建 Dispatch 对象时,响应的类型和请求的类型决定。

单向调用

当请求没有生成响应时,使用 Dispatch 对象的 calls OneWay ()进行远程调用例 41.7 “Dispatch.invokeOneWay () 方法” 显示此方法的签名。

例 41.7. Dispatch.invokeOneWay () 方法

invokeOneWayTmsgWebServiceException

用于在创建 Dispatch 对象时确定用于对请求打包的对象类型。例如,如果使用 createDispatch (portName, DOMSource.class, Service.Mode.PAYLOAD) 创建 Dispatch 对象,则请求会打包成 DOMSource 对象。

注意

在使用 JAXB 对象时,响应和请求可以是提供的 JAXBContext 对象的任何类型。

例 41.8 “使用 Dispatch 对象进行一次性调用” 显示使用 JAXB 对象在远程服务上进行单向调用的代码。

例 41.8. 使用 Dispatch 对象进行一次性调用

// Creating a JAXBContext and an Unmarshaller for the request
JAXBContext jbc = JAXBContext.newInstance("org.apache.cxf.StockExample");
Unmarshaller u = jbc.createUnmarshaller();

// Read the request from disk
File rf = new File("request.xml");
GetStockPrice request = (GetStockPrice)u.unmarshal(rf);

// Dispatch disp created previously
disp.invokeOneWay(request);