第 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. 使用模式
概述
分配对象有两种 使用模式 :
- 消息 模式
- 消息 Payload 模式(Payload 模式)
为 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 对象调用远程服务,应遵循以下序列:
创建 Dispatch 对象
-
创建一个
Service
对象来代表wsdl:service
元素,该元素定义 Dispatch 对象将发出调用的服务。请参阅 第 25.2 节 “创建服务对象”。 使用
Service
对象的createDispatch ()
方法创建 Dispatch 对象,如 例 41.1 “createDispatch ()
方法” 所示。例 41.1.
createDispatch ()
方法Public
Dispatch<T
>createDispatch
QName
portName
java.lang.Class<T&
gt;type
Service.Mode
mode
WebServiceException注意如果您使用 JAXB 对象,则
createDispatch ()
的方法签名为:public Dispatch<T>
;createDispatch
QName
portName
javax.xml.bind.JAXBContext
context
Service.Mode
mode
WebServiceException表 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 ()
方法
T
invoke
T
msg
WebServiceException
在创建 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>
invokeAsync
T
msg
WebServiceException
有关使用轮询方法进行异步调用的详细信息,请参阅 第 40.4 节 “使用轮询方法实施同步客户端”。
在使用回调方法时,invokeAsync ()
方法采用 AsyncHandler 实现,它会在返回时处理响应。例 41.6 “使用回调的 Dispatch.invokeAsync ()
方法” 显示使用回调方法进行异步调用的方法签名。
例 41.6. 使用回调的 Dispatch.invokeAsync ()
方法
future<?>
;invokeAsync
T
msg
AsyncHandler<T>
;handler
WebServiceException
有关使用回调方法进行异步调用的详情,请参考 第 40.5 节 “使用回调方法实施同步客户端”。
与同步 调用
() 方法一样,在创建 Dispatch 对象时,响应的类型和请求的类型会被决定。
单向调用
当请求没有生成响应时,请使用 Dispatch 对象的 invokeOneWay ()
进行远程调用。例 41.7 “Dispatch.invokeOneWay ()
方法” 显示此方法的签名。
例 41.7. Dispatch.invokeOneWay ()
方法
invokeOneWay
T
msg
WebServiceException
用于在创建 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);