第 41 章 使用 Raw XML 消息


摘要

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

41.1. 在一个 Consumer 中使用 XML

摘要

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

41.1.1. 使用模式

概述

分配对象有两种 使用模式

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

消息模式

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

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

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

有效负载模式

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

当使用不使用特殊打包程序的绑定时,如 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 文档的低级别对象。每个源实施都提供了访问存储的 XML 文档的方法,然后操作其内容。以下对象实现 Source 接口:

DOMSource
包含 XML 消息作为文档对象模型(DOM)树。XML 消息作为一组使用 get Node () 方法访问的节点对象保存。节点可以使用 setNode () 方法更新或添加到 DOM 树中。
SAXSource
包含 XML 消息作为 XML (SAX)对象的简单 API。SAX 对象包含一个 InputSource 对象,其中包含原始数据和 XMLReader 对象来解析原始数据。
StreamSource
包含 XML 消息作为数据流。数据流可以像任何其他数据流一样操作。

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

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

使用 SOAPMessage 对象

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

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

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

使用 DataSource 对象

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

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

数据源对象提供了一种使用来自各种源的 MIME 类型数据的机制,包括 URL、文件和字节数组。

使用 JAXB 对象

虽然 Dispatch 对象旨在低级 API,允许您处理原始消息,它们也允许您使用 JAXB 对象。若要使用 JAXB 对象,必须传递一个 JAXBContext,该对象可以使用 marshal 和 unmarshal。当创建 Dispatch 对象时,会传递 JAXBContext

您可以将 JAXBContext 对象理解的任何 JAXB 对象作为参数传递给 invoke () 方法。您还可以将返回的消息定向到 JAXBContext 对象理解的任何 JAXB 对象。

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

41.1.3. 使用 Dispatch 对象

步骤

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

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

创建 Dispatch 对象

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

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

    例 41.1. createDispatch () 方法

    PublicDispatch<T>createDispatchQNameportNamejava.lang.Class<T&gt;typeService.ModemodeWebServiceException

    注意

    如果您使用 JAXB 对象,则 createDispatch () 的方法签名为:public Dispatch&lt;T&gt;createDispatchQNameportNamejavax.xml.bind.JAXBContextcontextService.ModemodeWebServiceException

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

    表 41.1. createDispatch ()的参数
    参数描述

    portName

    指定代表服务供应商的 wsdl:port 元素的 QName,其中 Dispatch 对象将发出调用。

    type

    指定 Dispatch 对象使用的对象类型。请参阅 第 41.1.2 节 “数据类型”。使用 JAXB 对象时,此参数指定用于 marshal 和 unmarshal 的 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 架构文档提供。虽然服务提供商有很大变化,但需要遵循几个准则:

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

    警告

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

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

    重要

    顶级元素的子项可以是命名空间限定性。要确定,您必须检查其架构定义。

  • 如果被调用的服务使用 rpc/literal 信息,则任何顶级元素都不为空。
  • 如果被调用的服务使用 doc/literal 消息,消息的 schema 定义将确定是否有任何元素是否合格。

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

同步调用

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

例 41.3. Dispatch.invoke () 方法

TinvokeTmsgWebServiceException

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

注意

使用 JAXB 对象时,响应和请求可以是提供的 JAXBContext 对象可以 marshal 和 unmarshal 的任何类型。此外,响应和请求也可以是不同的 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 对象可以使用轮询方法和回调方法。

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

例 41.5. 轮询的 Dispatch.invokeAsync () 方法

Response <T>invokeAsyncTmsgWebServiceException

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

在使用回调方法时,invokeAsync () 方法采用 AsyncHandler 实现,它会在返回时处理响应。例 41.6 “使用回调的 Dispatch.invokeAsync () 方法” 显示使用回调方法进行异步调用的方法签名。

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

future<?&gt;invokeAsyncTmsgAsyncHandler<T&gt;handlerWebServiceException

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

注意

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

单向调用

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

例 41.7. Dispatch.invokeOneWay () 方法

invokeOneWayTmsgWebServiceException

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

注意

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

例 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);
Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.