使用 JAX-WS API 开发动态客户机
Java™ API for XML-Based Web Services (JAX-WS) 支持对服务端点操作进行动态调用。
关于此任务
JAX-WS 提供新的动态 Dispatch client API,此 API 更通用,并且比现有的基于 Java API for XML-based RPC (JAX-RPC) 的动态调用接口 (DII) 更灵活。Dispatch client 接口 javax.xml.ws.Dispatch 是面向 XML 消息传递的客户机,适用于更喜欢使用 XML 构造在 XML 级别工作的高级 XML 开发者。要编写 Dispatch client,必须具有 Dispatch client API 和受支持的对象类型方面的专门知识,并了解关联 Web Service 描述语言 (WSDL) 文件的消息表示。
Dispatch API 可以在 PAYLOAD 或 MESSAGE 方式下发送数据。使用 PAYLOAD 方式时,Dispatch client 仅负责提供 <soap:Body> 的内容,而 JAX-WS 在 <soap:Envelope> 元素中包含输入有效内容。使用 MESSAGE 方式时,Dispatch client 负责提供整个 SOAP 包络。
- javax.xml.transform.Source:使用 Source 对象启用客户机以直接使用 XML API。可以将 Source 对象与 SOAP 和 HTTP 绑定配合使用。
- JAXB 对象:借助 JAXB 对象,客户机可以通过根据 XML 模式生成的 JAXB 对象,使用 JAX-WS 应用程序来创建和控制 XML。JAXB 对象只能与 SOAP 和 HTTP 绑定配合使用。
- javax.xml.soap.SOAPMessage:借助 SOAPMessage 对象,客户机可以处理 SOAP 消息。只能将 SOAPMessage 对象与 SOAP V1.1 或 SOAP V1.2 绑定配合使用。
- javax.activation.DataSource:借助 DataSource 对象,客户机可以处理多用途因特网邮件扩充协议 (MIME) 消息。DataSource 仅与 HTTP 绑定配合使用。
过程
结果
从 WebSphere® Application Server V8.0 开始,使用服务方法 addPort 添加的那些 JAX-WS 动态端口可能需要更多内存。在前发行版中,可以在多个服务实例之间共享动态端口的单个实例。在 V8.x 中,现在已将动态端口的范围限定为添加这些端口的服务实例。如果 JAX-WS 客户机有多个服务实例引用了同名的动态端口,那么将不再共享这些实例。这可能会增加该客户机的内存需求。当服务实例不在范围内时,将释放动态端口所使用的内存。但是,如果遇到与增加的内存用量相关的问题,那么可以还原该行为,以便在服务实例之间再次共享动态端口。要这样做,请将系统属性 jaxws.share.dynamic.ports.enable 设置为值 true。 但是,请注意,这样做可能会导致其他问题,例如在共享的动态端口之间未正确地应用策略集连接。如果将此标记设置为 true 并遇到这些问题中的某些问题,那么应该移除该标记设置。
在前发行版中,如果 Dispatch 客户机应用程序未提供 SOAP 操作,那么不会在出站消息上发送正确的 SOAP 操作。而是将 SOAP 操作设置为匿名操作。 从 WebSphere Application Server V8 开始,如果 Dispatch 客户机应用程序未提供 SOAP 操作,那么 JAX-WS 运行时环境将解析外发消息。它会确定正在调用的操作并使用该信息来确定适用于 SOAP 操作的相应值。出站消息的操作解析基于 SOAP 主体和消息编码(例如 Doc/Lit/Bare 和 Doc/Lit/Wrapped)。由于这种解析开销很大,所以可以设置一个属性。要始终禁用解析,请在系统级别设置该属性。要按消息来禁用解析,请在 JAX-WS 请求消息上下文上设置该属性。该属性定义为常量 org.apache.axis2.jaxws.Constants.DISPATCH_CLIENT_OUTBOUND_RESOLUTION 且具有字符串值 jaxws.dispatch.outbound.operation.resolution.enable。 属性的缺省值是空值,该解释为字符串 True,这将启用出站操作解析。将该属性设置为 False 可禁用出站操作解析。如果禁用解析,那么会按照先前步骤中所示,将出站消息中的 SOAP 操作设置为匿名操作。如果客户机通过 JAX-WS javax.xml.ws.BindingProvider 属性 SOAPACTION_USE_PROPERTY 和 SOAPACTION_URI_PROPERTY 提供了 SOAP 操作,那么将使用该 SOAP 操作。因此,无论该属性的设置为何,都不会解析出站消息。 通过客户机来显式设置 SOAP 操作是最佳实践,这尤其适用于服务提供程序的性能。此实践可阻止解析入站消息,以将入站消息路由到正确的端点操作。
示例
String endpointUrl = ...;
QName serviceName = new QName("http://com/ibm/was/wssample/echo/",
"EchoService");
QName portName = new QName("http://com/ibm/was/wssample/echo/",
"EchoServicePort");
/** Create a service and add at least one port to it. **/
Service service = Service.create(serviceName);
service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointUrl);
/** Create a Dispatch instance from a service.**/
Dispatch<SOAPMessage> dispatch = service.createDispatch(portName,
SOAPMessage.class, Service.Mode.MESSAGE);
/** Create SOAPMessage request. **/
// compose a request message
MessageFactory mf = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
// Create a message. This example works with the SOAPPART.
SOAPMessage request = mf.createMessage();
SOAPPart part = request.getSOAPPart();
// Obtain the SOAPEnvelope and header and body elements.
SOAPEnvelope env = part.getEnvelope();
SOAPHeader header = env.getHeader();
SOAPBody body = env.getBody();
// Construct the message payload.
SOAPElement operation = body.addChildElement("invoke", "ns1",
"http://com/ibm/was/wssample/echo/");
SOAPElement value = operation.addChildElement("arg0");
value.addTextNode("ping");
request.saveChanges();
/** Invoke the service endpoint. **/
SOAPMessage response = dispatch.invoke(request);
/** Process the response. **/