41.2. 在服务提供商中使用 XML
摘要
Provider 接口是一个低级 JAX-WS API,允许您实施直接将消息用作原始 XML 的服务提供商。在将消息传递给实施提供程序接口的对象之前,消息不会打包到 JAXB 对象。
41.2.1. 消息传递模式
概述
实施提供程序接口的对象有两种 消息传递模式 :
您指定的消息传递模式决定了传递给您的实施的消息传递详情级别。
消息模式
使用 消息模式 时,Provider 实现可用于完整的消息。完整的消息包括任何绑定特定的标头和打包程序。例如,使用 SOAP 绑定的 Provider 实现会接收请求完全指定的 SOAP 消息。从实施返回的任何响应都必须是完全指定的 SOAP 消息。
要指定 Provider 实现使用消息模式,方法是提供值 java.xml.ws.Service.Mode.MESSAGE 作为 javax.xml.ws.ServiceMode
注解的值,如 例 41.9 “指定提供程序实施使用消息模式” 所示。
例 41.9. 指定提供程序实施使用消息模式
@WebServiceProvider @ServiceMode(value=Service.Mode.MESSAGE) public class stockQuoteProvider implements Provider<SOAPMessage> { ... }
有效负载模式
在 有效负载模式中,提供程序实施仅适用于消息的载荷。例如,在有效负载模式下工作的提供程序实施仅适用于 SOAP 消息的正文。绑定层处理任何绑定级别打包程序和标头。
当使用不使用特殊打包程序的绑定时,如 Apache CXF XML 绑定、有效负载模式和消息模式会提供相同的结果。
要指定 Provider 实现使用有效负载模式,方法是提供 java.xml.ws.Service.Mode.PAYLOAD 值作为 javax.xml.ws.ServiceMode
注解的值,如 例 41.10 “指定供应商实施使用 Payload 模式” 所示。
例 41.10. 指定供应商实施使用 Payload 模式
@WebServiceProvider @ServiceMode(value=Service.Mode.PAYLOAD) public class stockQuoteProvider implements Provider<DOMSource> { ... }
如果没有为 @ServiceMode
注释提供值,则 Provider 实现将使用有效负载模式。
41.2.2. 数据类型
概述
由于它们是低级对象,因此提供程序实施无法使用与更高级别的消费者 API 相同的 JAXB 生成的类型。供应商实现可用于以下类型的对象:
使用 Source 对象
提供程序实施可以接受和返回从 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 消息作为数据流。数据流可以像任何其他数据流一样操作。
如果您创建 Provider 对象使其使用通用 Source 对象,则 Apache CXF 会将消息返回为 SAXSource
对象。
可以使用端点的 source-preferred-format
属性来更改此行为。有关配置 Apache CXF 运行时的详情,请参考 第 IV 部分 “配置 Web 服务端点”。
在使用 Source 对象时,开发人员负责确保所有需要的绑定特定打包程序都添加到消息中。例如,当与期望 SOAP 消息的服务交互时,开发人员必须确保所需的 SOAP 环境elope 添加到传出请求中,并且 SOAP 信封内容正确。
使用 SOAPMessage 对象
当以下条件为 true 时,供应商实现可以使用 javax.xml.soap.SOAPMessage
对象:
- Provider 实现使用 SOAP 绑定
- Provider 实现使用消息模式
SOAPMessage
对象包含 SOAP 消息。它们包含一个 SOAPPart
对象和零个或多个 AttachmentPart
对象。SOAPPart
对象包含 SOAP 消息的特定部分,包括 SOAP 信封、任何 SOAP 标头和 SOAP 消息正文。AttachmentPart
对象包含作为附件传递的二进制数据。
使用 DataSource 对象
当满足以下条件时,供应商实现可以使用 javax.activation.DataSource 接口的对象:
- 实现使用 HTTP 绑定
- 实现使用消息模式
数据源对象提供了一种使用来自各种源的 MIME 类型数据的机制,包括 URL、文件和字节数组。
41.2.3. 实施提供程序对象
概述
提供商界面相对容易实施。它只有一个必须实施的方法 invoke ()
。另外,它有三个简单的要求:
-
实施必须具有
@WebServiceProvider
注释。 - 实施必须具有默认的公共构造器。
实施必须实施类型化的 Provider 接口版本。
换句话说,您无法实施 Provider<T> 接口。您必须实现一个使用 第 41.2.2 节 “数据类型” 中列出的聚合数据类型的接口版本。例如,您可以实施 Provider<SAXSource> 的实例。
实施 Provider 接口的复杂性位于处理请求消息的逻辑中,并构建正确的响应。
使用消息
与基于更高级别的 SEI 的服务实现不同,提供程序实施将请求作为原始 XML 数据接收,且必须发送响应作为原始 XML 数据。这要求开发人员熟悉所实施的服务所使用的消息。这些详细信息通常可在描述该服务的 WSDL 文档中找到。
WS-I Basic Profile 提供有关服务使用的消息的指南,包括:
请求的根元素基于与调用的操作对应的
wsdl:operation
元素的name
属性的值。警告如果服务使用 doc/literal 裸机消息,则请求的 root 元素将基于
wsdl:part
元素的name
属性的值,引用由wsdl:operation
元素引用。- 所有消息的 root 元素都是命名空间限定性。
如果服务使用 rpc/literal 消息,则消息中的顶级元素不是命名空间限定性。
重要顶级元素的子项可能具有命名空间限定性,但要确保您必须检查其架构定义。
- 如果服务使用 rpc/literal 消息,则顶级元素中的任何一个都是 null。
- 如果服务使用 doc/literal 信息,则消息的 schema 定义确定了任何元素是否合格。
@WebServiceProvider 注释
若要被 JAX-WS 识别为服务实施,提供程序实施必须使用 @WebServiceProvider
注释进行解码。
表 41.2 “@WebServiceProvider
Properties” 描述可以为 @WebServiceProvider
注释设置的属性。
属性 | 描述 |
---|---|
|
指定定义服务端点的 |
|
指定包含服务端点的 |
| 指定服务的 WSDL 定义的目标名称空间。 |
| 指定定义该服务的 WSDL 文档的 URI。 |
所有这些属性都是可选的,默认为空。如果您将其留空,Apache CXF 将使用实施类中的信息创建值。
实施 invoke ()方法
Provider 接口只有一个方法 invoke ()
,必须实施它。invoke ()
方法接收被实施的 Provider 接口声明的传入请求,并返回打包到同一类型的对象中的响应消息。例如,一个 Provider<SOAPMessage> 接口的实现会接收作为 SOAPMessage
对象的请求,并将响应返回为 SOAPMessage
对象。
提供程序实施使用的消息传递模式决定了请求包含的绑定特定信息的数量。使用消息模式实施会接收所有绑定特定的打包程序和标头以及请求。它们还必须将所有绑定特定打包程序和标头添加到响应消息。使用有效负载模式的实现仅接收请求的正文。使用有效负载模式返回的 XML 文档被放在请求消息的正文中。
例子
例 41.11 “provider<SOAPMessage> 实现” 显示在消息模式中与 SOAPMessage
对象配合使用的 Provider 实现。
例 41.11. provider<SOAPMessage> 实现
import javax.xml.ws.Provider; import javax.xml.ws.Service; import javax.xml.ws.ServiceMode; import javax.xml.ws.WebServiceProvider; @WebServiceProvider(portName="stockQuoteReporterPort" serviceName="stockQuoteReporter") @ServiceMode(value="Service.Mode.MESSAGE") public class stockQuoteReporterProvider implements Provider<SOAPMessage> { public stockQuoteReporterProvider() { } public SOAPMessage invoke(SOAPMessage request) { SOAPBody requestBody = request.getSOAPBody(); if(requestBody.getElementName.getLocalName.equals("getStockPrice")) { MessageFactory mf = MessageFactory.newInstance(); SOAPFactory sf = SOAPFactory.newInstance(); SOAPMessage response = mf.createMessage(); SOAPBody respBody = response.getSOAPBody(); Name bodyName = sf.createName("getStockPriceResponse"); respBody.addBodyElement(bodyName); SOAPElement respContent = respBody.addChildElement("price"); respContent.setValue("123.00"); response.saveChanges(); return response; } ... } }
例 41.11 “provider<SOAPMessage> 实现” 中的代码执行以下操作:
指定以下类实施实施 wsdl:service
元素的服务的 Provider 对象,其名为 stockQuoteReporter
,其 wsdl:port
元素名为 stockQuoteReporterPort
。
指定此 Provider 实现使用消息模式。
提供所需的默认公共构造器。
提供使用 SOAPMessage
对象并返回 SOAPMessage
对象的 invoke ()
方法的实现。
从传入 SOAP 消息的正文中提取请求消息。
检查请求消息的 root 元素,以确定如何处理请求。
创建构建响应所需的工厂。
为响应构建 SOAP 消息。
将响应返回为 SOAPMessage
对象。
例 41.12 “Provider<DOMSource> 实现” 显示了在有效负载模式中使用 DOMSource
对象进行提供程序实施的示例。
例 41.12. Provider<DOMSource> 实现
import javax.xml.ws.Provider; import javax.xml.ws.Service; import javax.xml.ws.ServiceMode; import javax.xml.ws.WebServiceProvider; @WebServiceProvider(portName="stockQuoteReporterPort" serviceName="stockQuoteReporter") @ServiceMode(value="Service.Mode.PAYLOAD") public class stockQuoteReporterProvider implements Provider<DOMSource> public stockQuoteReporterProvider() { } public DOMSource invoke(DOMSource request) { DOMSource response = new DOMSource(); ... return response; } }
例 41.12 “Provider<DOMSource> 实现” 中的代码执行以下操作:
指定该类实施服务(其 wsdl:service
元素名为 stockQuoteReporter
)的 Provider 对象,其 wsdl:port
元素名为 stockQuoteReporterPort
。
指定此提供程序实施使用有效负载模式。
提供所需的默认公共构造器。
提供使用 DOMSource
对象并返回 DOMSource
对象的 invoke ()
方法的实现。