JAX-RPC 与 JAX-WS 的比较,第 5 部分:附件文件比较:Sw/A 与 MTOM
2009-11-03 00:00:00 来源:WEB开发网引言
JAX-RPC 的附件模型为 Sw/A,自从编写 JAX-RPC 后,就推出了一个新的附件模型:MTOM。JAX-WS 和 JAX-RPC 一样提供了 Sw/A 支持,但还增加了对 MTOM 的支持。JAX-WS 通过 Java Architecture for XML Binding (JAXB) 规范支持 MTOM,此规范包括用于对 Sw/A 和 MTOM 附件进行封送和取消封送。在本文中,我们将通过示例对这两个模型进行分析。请注意:本文仅对 WSDL 和 Java 编程模型进行比较,连接级别的消息比较需由读者自行完成。
JAX-RPC 和 Sw/A 示例
清单 1 给出了摘自多年前所撰写的关于附件提示的 WSDL。清单 2 显示了对应的 Java 接口(即从此 WSDL 生成的 JAX-RPC 映射)。
清单 1. JAX-RPC Sw/A WSDL<definitions
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://attachment.tip/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
targetNamespace="http://attachment.tip/">
<types/>
<message name="sendImage">
<part name="image" type="xsd:base64Binary"/>
</message>
<message name="sendImageResponse"/>
<message name="sendOctet">
<part name="octet" type="xsd:base64Binary"/>
</message>
<message name="sendOctetResponse"/>
<portType name="AttachmentTip">
<operation name="sendImage">
<input message="tns:sendImage"/>
<output message="tns:sendImageResponse"/>
</operation>
<operation name="sendOctet">
<input message="tns:sendOctet"/>
<output message="tns:sendOctetResponse"/>
</operation>
</portType>
<binding name="AttachmentBinding" type="tns:AttachmentTip">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="sendImage">
<soap:operation soapAction=""/>
<input>
<mime:multipartRelated>
<mime:part>
<soap:body parts="" namespace="http://attachment.tip/" use="literal"/>
</mime:part>
<mime:part>
<mime:content part="image" type="image/jpeg"/>
</mime:part>
</mime:multipartRelated>
</input>
<output>
<soap:body namespace="http://attachment.tip/" use="literal"/>
</output>
</operation>
<operation name="sendOctet">
<soap:operation soapAction=""/>
<input>
<mime:multipartRelated>
<mime:part>
<soap:body parts="" namespace="http://attachment.tip/" use="literal"/>
</mime:part>
<mime:part>
<mime:content part="octet" type="application/octet-stream"/>
</mime:part>
</mime:multipartRelated>
</input>
<output>
<soap:body namespace="http://attachment.tip/" use="literal"/>
</output>
</operation>
</binding>
<service name="AttachmentService">
<port binding="tns:AttachmentBinding" name="AttachmentTip">
<soap:address location="http://localhost:9080/SwAService/services/AttachmentTip"/>
</port>
</service>
</definitions>
清单 2. JAX-RPC Sw/A Java 接口package tip.attachment;
import java.awt.Image;
import java.rmi.Remote;
import java.rmi.RemoteException;
import javax.activation.DataHandler;
public interface AttachmentTip extends Remote {
public void sendImage(Image image) throws RemoteException;
public void sendOctet(DataHandler octet) throws RemoteException;
}
从 WSDL 生成的 Java 接口映射相当简单:sendImage 操作的 image/jpeg 部分映射为 java.awt.Image 参数;sendOctet 操作的 application/octet-stream 映射为 javax.activation.DataHandler 参数。不过此映射有一定的代价:多用途 Internet 邮件扩展(Multipurpose Internet Mail Extensions,MIME)类型信息不在 WSDL 接口部分中(portType、message 和 types 部分)。您必须自己对绑定进行分析,以找到 MIME 信息。这很不方便,因为相同 WSDL 接口的不同绑定可能会采用不同的类型,从而映射到不同的 Java 接口。如果从 WSDL 接口到 Java 接口之间存在一对一映射关系,这就要好得多。如果有多个绑定,每个都映射到一个实现,则所有绑定都实现相同的 Java 接口。使用 Sw/A 时不能做到这一点;从 WSDL 到 Java 的映射不是一对一的。
Sw/A 的第二个问题是,它本身对 Document/literal Wrapped WSDL 行业惯例遵循性并不好(您会注意到清单 1 中的 WSDL 是 rpc/literal WSDL)。要将 Sw/A 内容添加到 Document/literal Wrapped 消息,除了单个操作包装外,还需要指定其他消息部分。
MTOM 是否解决了这些问题?接下来我们就要对此进行讨论。
JAX-WS 和 MTOM 示例
在清单 3 中,我们将清单 1 的 Sw/A WSDL 修改为了等效的 MTOM WSDL。
清单 3. JAX-WS MTOM WSDL<definitions
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://attachment.tip/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://attachment.tip/">
<types/>
<message name="sendImage">
<part name="image" type="xsd:base64Binary"/>
</message>
<message name="sendImageResponse"/>
<message name="sendOctet">
<part name="octet" type="xsd:base64Binary"/>
</message>
<message name="sendOctetResponse"/>
<portType name="AttachmentTip">
<operation name="sendImage">
<input message="tns:sendImage"/>
<output message="tns:sendImageResponse"/>
</operation>
<operation name="sendOctet">
<input message="tns:sendOctet"/>
<output message="tns:sendOctetResponse"/>
</operation>
</portType>
<binding name="AttachmentBinding" type="tns:AttachmentTip">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="sendImage">
<soap:operation soapAction=""/>
<input>
<soap:body namespace="http://attachment.tip/" use="literal"/>
</input>
<output>
<soap:body namespace="http://attachment.tip/" use="literal"/>
</output>
</operation>
<operation name="sendOctet">
<soap:operation soapAction=""/>
<input>
<soap:body namespace="http://attachment.tip/" use="literal"/>
</input>
<output>
<soap:body namespace="http://attachment.tip/" use="literal"/>
</output>
</operation>
</binding>
<service name="AttachmentService">
<port binding="tns:AttachmentBinding" name="AttachmentTip">
<soap:address location="http://localhost:9080/MTOMService/services/AttachmentTip"/>
</port>
</service>
</definitions>
清单 3 中的 MTOM WSDL 和清单 1 中的 Sw/A WSDL 的唯一区别在于绑定。MTOM 绑定不包含 MIME 信息。事实上,通过 WSDL 并不能说明您所处理的是附件,WSDL 的绑定看起来就像一个普通绑定。
清单 4 显示了对应的 Java 接口,即从此 WSDL 生成的 JAX-RPC 映射。
清单 4. JAX-WS MTOM Java 接口package tip.attachment;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
@WebService(name = "AttachmentTip", targetNamespace = "http://attachment.tip/")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface AttachmentTip {
@WebMethod
public void sendImage(
@WebParam(name = "image", partName = "image")
byte[] image);
@WebMethod
public void sendOctet(
@WebParam(name = "octet", partName = "octet")
byte[] octet);
}
因为此 WSDL 是普通 WSDL,没有关于附件的信息,因此最终得到的 Java 接口也会反映出这一点。对于类型为 base64Binary(或 hexBinary)的部分,JAX-WS 将其映射为 byte[] 类型的参数。对于 MTOM,会从 WSLD 提取类型的全部 MIME 信息,并需要由客户机或服务器运行时对内容进行恰当的格式化。
Sw/A 和 MTOM 的比较
JAX-RPC Sw/A 部分指出了 Sw/A 的两个缺点:
MIME 类型信息在 WSDL 绑定中,而不是 WSDL 接口中。
很难创建 Document/literal Wrapped 附件 WSDL。
让我们首先讨论一下 Document/literal Wrapped 样式。
Document/literal Wrapped 样式与附件
出于比较目的,我们将清单 3 中的 MTOM WSDL 保留为 rpc/literal WSDL;但要将此 WSDL 转换为 Document/literal Wrapped WSDL 很容易。下一部分的清单 5 显示了清单 3 中的 WSDL 的 Document/literal Wrapped 等效 WSDL。
绑定中的 MIME 类型信息
因为 MTOM WSDL 的绑定没有任何 MIME 信息,因此不用分析绑定来确定部分类型。在 WSDL 中有生成 Java 接口所需要的全部信息。不过,正如您通过比较清单 2 和清单 4 可以看到的,我们丢失了一些信息。
这两个 WSDL 的接口部分都显示操作中的数据类型为 base64Binary,而 base64Binary 又映射到 byte[]。不过,在 JAX-RPC Sw/A WSDL 中,我们通过绑定了解到部分类型为 MIME 映像和 MIME 八进制流。在 JAX-WS MTOM WSDL 中,此信息丢失了。这可能让人感觉是件坏事,但有一个好处,即接口得到了完全的清理。无论绑定的是什么,接口始终都是一样的。事实上,客户机和服务器代码库的实现者不应考虑参数是否是附件的问题。这仅是 SOAP 消息的一个细节,WSDL 到 Java 映射的编写者已经尽量让程序员不考虑 SOAP 消息的细节。
不过,如果您真的希望知道 MIME 类型(即希望找回所丢失的信息),JAX-WS 提供了一个属性,您可将其注入 XML 元素:expectedContentTypes 中。清单 5 中突出显示的部分就是这个特殊的属性。清单 6 显示了对应的 Java 接口。如果忽略注释,此 Java 接口就完全与清单 2 中的接口相同。
清单 5. JAX-WS MIME 属性<definitions
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://attachment.tip/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://attachment.tip/">
<types>
<xsd:schema
xmlns:tns="http://attachment.tip/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://attachment.tip/">
<xsd:element name="sendImage" type="tns:sendImage"/>
<xsd:complexType name="sendImage">
<xsd:sequence>
<xsd:element
xmlns:ns1="http://www.w3.org/2005/05/xmlmime"
ns1:expectedContentTypes="image/*"
name="image"
type="xsd:base64Binary"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="sendImageResponse" type="tns:sendImageResponse"/>
<xsd:complexType name="sendImageResponse">
<xsd:sequence/>
</xsd:complexType>
<xsd:element name="sendOctet" type="tns:sendOctet"/>
<xsd:complexType name="sendOctet">
<xsd:sequence>
<xsd:element
xmlns:ns1="http://www.w3.org/2005/05/xmlmime"
ns1:expectedContentTypes="application/octet-stream"
name="octet"
type="xsd:base64Binary"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="sendOctetResponse" type="tns:sendOctetResponse"/>
<xsd:complexType name="sendOctetResponse">
<xsd:sequence/>
</xsd:complexType>
</xsd:schema>
</types>
<message name="sendImage">
<part name="parameters" element="tns:sendImage"/>
</message>
<message name="sendImageResponse">
<part name="parameters" element="tns:sendImageResponse"/>
</message>
<message name="sendOctet">
<part name="parameters" element="tns:sendOctet"/>
</message>
<message name="sendOctetResponse">
<part name="parameters" element="tns:sendOctetResponse"/>
</message>
<portType name="AttachmentTip">
<operation name="sendImage">
<input message="tns:sendImage"/>
<output message="tns:sendImageResponse"/>
</operation>
<operation name="sendOctet">
<input message="tns:sendOctet"/>
<output message="tns:sendOctetResponse"/>
</operation>
</portType>
<binding name="AttachmentBinding" type="tns:AttachmentTip">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="sendImage">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
<operation name="sendOctet">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="AttachmentService">
<port binding="tns:AttachmentBinding" name="AttachmentTip">
<soap:address location="http://localhost:9080/MTOMService/services/AttachmentTip"/>
</port>
</service>
</definitions>
请注意,这个新属性完全包含在 WSDL 接口中。该属性不在绑定中,因此所有类型信息都在您所期望的位置。
清单 6. 从 MIME 属性映射得到的 JAX-WS Java 接口package tip.attachment;
import java.awt.Image;
import javax.activation.DataHandler;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
@WebService(name = "AttachmentTip", targetNamespace = "http://attachment.tip/")
public interface AttachmentTip {
@WebMethod
@RequestWrapper(localName = "sendImage",
targetNamespace = "http://attachment.tip/",
className = "tip.attachment.SendImage")
@ResponseWrapper(localName = "sendImageResponse",
targetNamespace = "http://attachment.tip/",
className = "tip.attachment.SendImageResponse")
public void sendImage(
@WebParam(name = "image", targetNamespace = "")
Image image);
@WebMethod
@RequestWrapper(localName = "sendOctet",
targetNamespace = "http://attachment.tip/",
className = "tip.attachment.SendOctet")
@ResponseWrapper(localName = "sendOctetResponse",
targetNamespace = "http://attachment.tip/",
className = "tip.attachment.SendOctetResponse")
public void sendOctet(
@WebParam(name = "octet", targetNamespace = "")
DataHandler octet);
}
正如前面所提到的,JAX-WS 依赖于 JAXB 处理其大部分 Web 服务内容的数据绑定。expectedContentTypes 元素的映射在 JAXB 2.0 规范的附录 H 中定义。JAXB 2.0 映射与 JAX-RPC 映射类似。表 1 对这些映射进行了比较。
表 1. MIME 类型到 Java 类型的映射
MIME 类型 | JAX-RPC 映射 | JAX-WS/JAXB 映射 |
image/gif | java.awt.Image | java.awt.Image |
image/jpg | java.awt.Image | java.awt.Image |
text/plain | java.lang.String | javax.xml.transform.Source |
text/xml | javax.xml.transform.Source | javax.xml.transform.Source |
application/xml | javax.xml.transform.Source | javax.xml.transform.Source |
multipart/* | javax.mail.internet.MimeMultipart | javax.activation.DataHandler |
所有其他类型 | javax.activation.DataHandler | javax.activation.DataHandler |
启用/禁用附件支持
MTOM 的另外一个好处是,您能够启用或禁用它。对于 Sw/A,如果某一方不支持发送 Sw/A 附件,就不能遵守 WSDL 定义的契约。另一方面,如果使用清单 3 或清单 5 中给出的类似的 MTOM WSDL,客户机就可以选择将数据作为 MTOM 附件发送或在 SOAP 消息中以内联方式发送。无论客户机选择哪个选项,都仍然可以与 Web 服务交互。MTOM 只是发送内容的一个优化选项,而不是像 Sw/A 一样强制要求使用。
Sw/A 和 JAX-WS
JAX-WS 仍然支持 Sw/A 模型。缺省情况下,JAX-WS 将 Sw/A 附件映射到 Java 接口上的 byte[],就像清单 4 中的示例一样。要获得在 JAX-RPC 中使用的映射,可以使用 enableMIMEContent WSDL 绑定定义(有关更多信息,请参见 JAX-WS 规范的 8.7.5 节)。清单 7 显示了与清单 2 中的接口的 JAX-RPC 版本等效的 JAX-WS 版本。
清单 7. JAX-WS Java 接口,Sw/A 附件从 mime:content 映射package tip.attachment;
import java.awt.Image;
import javax.activation.DataHandler;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
@WebService(name = "AttachmentTip", targetNamespace = "http://attachment.tip/")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface AttachmentTip {
@WebMethod
public void sendImage(
@WebParam(name = "image", partName = "image")
Image image);
@WebMethod
public void sendOctet(
@WebParam(name = "octet", partName = "octet")
DataHandler octet);
}
总结
JAX-RPC 支持 Sw/A 模型。JAX-WS 也支持 Sw/A,但另外还支持新的 MTOM 模型。从多方面而言,MTOM 都比 Sw/A 提高了不少:
创建 Java 接口所必需的全部信息现在都在 WSDL 接口中。
MTOM 可以在 Document/literal Wrapped WSDL 中使用。
MTOM 允许对附件进行优化,但并不像 Sw/A 一样对附件有强制要求。
更多精彩
赞助商链接