第 41 章 使用 Raw XML 消息
摘要
高级别 JAX-WS API 防止开发人员使用原生 XML 消息,将数据放入 JAXB 对象。然而,在有些情况下,最好直接访问传输的原始 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 文档的低级别对象。每个 Source 实施都提供访问存储的 XML 文档的方法,然后操作其内容。以下对象实施 Source 接口:
DOMSource
-
将 XML 消息作为文档对象模型(DOM)树保存。XML 消息存储为一组
Node
对象,这些对象通过getNode()
方法访问。可以使用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 对象
当以下条件为 true 时,分配对象可以使用 javax.xml.SOAPMessage
对象:
- Dispatch 对象使用 SOAP 绑定
- Dispatch 对象使用消息模式
SOAPMessage
对象包含 SOAP 消息。它们包含一个 SOAPPart
对象和零个或多个 AttachmentPart
对象。SOAPPart
对象包含 SOAP 消息的特定部分,包括 SOAP envelope、任何 SOAP 标头和 SOAP 消息正文。AttachmentPart
对象包含作为附件传递的二进制数据。
使用 DataSource 对象
当以下条件满足时,分配对象可以使用实现 javax.activation.DataSource 接口的对象:
- Dispatch 对象使用 HTTP 绑定
- Dispatch 对象使用消息模式
数据源对象提供了一种机制,用于处理各种来源中的数据,包括 URL、文件和字节数组。
使用 JAXB 对象
虽然 Dispatch 对象应该是低级 API,但可让您使用原始消息,但它们还允许您使用 JAXB 对象。若要搭配 JAXB 对象使用 Dispatch 对象,必须传递一个 JAXBContext
,该对象可以使用的 marshal 和 unmarshal 和 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&
gt;createDispatch
QName
portName
java.lang.Class<T&
gt;type
Service.Mode
mode
WebServiceException注意如果使用 JAXB 对象,则
createDispatch()
的方法签名是:publicDispatch<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 对象时,此参数指定用于聚合和联合 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 架构文档提供。虽然服务提供商有很大不同,但遵循一些指南:
请求的根元素基于与正在调用
的操作
对应的wsdl:operation
元素的值。警告如果正在调用的服务使用 doc/literal 裸机消息,则请求的根元素将基于
wsdl:operation
元素引用的wsdl:part
元素的值。- 请求的根元素是命名空间限定。
如果正在调用的服务使用 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()
方法的响应和传递到 invoke()方法的请求类型。例如,如果您使用 createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE)
创建 Dispatch 对象,则响应和请求都是 SOAPMessage
对象。
使用 JAXB 对象时,响应和请求可以是任何类型的 JAXBContext
对象,可以总结和解包。此外,响应和请求可以是不同的 JAXB 对象。
例 41.4 “使用 Dispatch 对象生成 Synchronous Invocation” 显示使用 DOMSource
对象对远程服务进行同步调用的代码。
例 41.4. 使用 Dispatch 对象生成 Synchronous Invocation
// 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 对象都可以使用轮询方法和回调方法。
使用轮询方法时,调用Async()
方法会返回一个 Response<t&
gt; 对象,该对象可以轮询来查看响应是否已到达。例 41.5 “用于轮询的 Dispatch.invokeAsync()
方法” 显示使用轮询方法进行异步调用的方法的签名。
例 41.5. 用于轮询的 Dispatch.invokeAsync()
方法
响应 <T&
gt; 调用Async
T
msg
WebServiceException
有关使用轮询方法进行异步调用的详情,请参考 第 40.4 节 “使用轮询方法实施同步客户端”。
在使用回调方法时,调用Async()
方法采取 AsyncHandler 实施,在返回时处理响应。例 41.6 “使用回调的 Dispatch.invokeAsync()
方法” 显示使用回调方法进行异步调用的方法的签名。
例 41.6. 使用回调的 Dispatch.invokeAsync()
方法
future<?&
gt; 调用Async
T
msg
AsyncHandler<T&
gt;handler
WebServiceException
有关使用回调方法进行异步调用的详情,请参考 第 40.5 节 “使用回调方法实施同步客户端”。
与同步 调用()
方法一样,在创建 Dispatch 对象时,响应的类型和请求类型决定。
Oneway invocation
当请求没有生成响应时,使用 Dispatch 对象的 calls OneWay()进行远程调用
。例 41.7 “Dispatch.invokeOneWay()
方法” 显示此方法的签名。
例 41.7. Dispatch.invokeOneWay()
方法
调用OneWay
T
msg
WebServiceException
用于在创建 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);