1. SOAP: 与 Web Service 无关
虽然SOAP可能是为了实现Web Service而被发明的,但实际上它可以被用在任何需要交换数据的场合(SOAP is an XML-based communication protocol and encoding format for inter-application communication)
让我们比较一下SOAP和现实生活中的信封:
-
信封只是一个壳,但必不可少,其作用就是让接收者一看就知道是一封信,而不是一束花.(SOAP Envelop元素必不可少)
-
信封对里面的信件内容一无所知,它也没规定里面必须是情书或者工资单. (SOAP 可以包裹任何内容)
-
信件可以由信封包着,交给邮局送达,也可以由熟人顺路带过去. (SOAP 与传输方式无关,HTTP, JMS, SMTP...)
-
信件接收者可以选择回信,也可以不回. (SOAP 是单向的)
是的,就像<<Web Service Security>>作者的比喻,SOAP是应用程序间的电子邮件
正是由于SOAP的这种灵活性,许多新的规范都在SOAP的基础上进行扩展和定制,像WS-Security, WS-Addressing等,无非就是定义了几个标准化的SOAP Header或SOAP Body元素
2. WSDL: 与 Runtime 无关
WSDL是Web Service的静态描述信息,主要是用于在客户程序的编码设计阶段告诉客户程序Web Service的信息,一旦客户程序在设计阶段获得了足够的信息,运行时根本不需要什么WSDL
或许某种情况下运行时需要WSDL的帮助吧,但我没有遇到过,如果你知道,请告诉我
portType其实就是Web服务的接口,但这个名字实在不直观,尤其对非英语国家的人来说,新版本的WSDL规范已经将portType改名为了 “Interface”
3. WSDL-SOAP Binding Style
就是所谓RPC与Document或者Wrapped,Literal与Encoding
先说Literal与Encoding
-
Literal就是不在SOAP消息中表明数据类型,而通过其它方式获知数据类型,这种方式是开发包相关的,没有什么标准;如<x>50</x>,单从SOAP消息,你无法判断50是数字还是字符串,而具体的类型可以在开发包将SOAP请求映射到具体的Service类时来确定并完成转换,对于返回值也一样,客户端可已通过SetReturnValueType(...)之类的方法告知开发包自己期待什么类型
-
Encoding就是在SOAP消息中携带类型信息,并且依据某种规则将数据编码传递,接收端可以根据类型信息和编码规则完成解码,获得原始数据;如<x xsi:type="xsd:string">50</x>
再看看RPC与Document
<envelope><body><myMethod><x>5</x><y>8</y></myMethod></body></envelope> (RPC/Literal)
<envelope><body><myMethod><x type=string>5</x><y type=int>8</y></myMethod></body></envelope> (RPC/Encoded)
|
<types> <schema> <element name="xElement" type="xsd:int"/> </schema> </types>
<message name="myMethodRequest"> <part name="x" element="xElement"/> </message> <message name="empty"/>
<portType name="PT"> <operation name="myMethod"> <input message="myMethodRequest"/> <output message="empty"/> </operation> </portType>
则对应的SOAP消息如下:
<soap:envelope> <soap:body> <xElement>5</xElement> </soap:body> </soap:envelope>
然而这种方式没有在SOAP消息中包含操作名,所以如果两个不同的操作具有相同的输入,开发包有可能无法决定把请求转发到哪个函数,为避免这种情况,开发包一般为每个操作的输入输出都产生具有唯一名称的Element,不管它们是否内容相同;或者作为开发者,你可以选择 Wrapped 风格
|
<types> <schema>
<element name="myMethod"/> <complexType> <sequence> <element name="x" type="xsd:int"/> </sequence> </complexType> </element>
</schema> </types> <message name="myMethodRequest"> <part name="parameters" element="myMethod"/> </message> <message name="empty"/>
<portType name="PT"> <operation name="myMethod"> <input message="myMethodRequest"/> <output message="empty"/> </operation> </portType>
对应的SOAP消息:
<soap:envelope> <soap:body> <myMethod> <x>5</x> </myMethod> </soap:body> </soap:envelope>
这种方式也具有明显的弱点:无法方便的处理重载,因为XML Schema不允许定义相同名称的元素;这样,即使你的后台编程语言支持函数重载,你也应该尽量避免使用
|
Document services and wrapped services are similar in that neither uses the SOAP encoding for data; it's just plain old XML schema.
4. UDDI:与 WSDL 无关
虽然都是描述Web Service的,但UDDI与WSDL各司其责;事实上,UDDI野心太大,定义了很多社会性的Attribute,而不局限于技术性的Web服务,如人工电话服务信息和传真服务信息都可以注册到UDDI中,描述性的东西很多(descriptive information )一些overviewURL 也都推荐指向文档,关于这点,参照目前UDDI的应用情况,我认为UDDI是过度设计了
UDDI注册表其实是一堆元数据的集合,元元数据...,元数据用tModel来表达,可以有不同的分类,通过tModel key来引用;当你试图用字符串表达什么东西时,你最好看看是否已经有了对应的tModel,有的话你就需要用对该tModel的引用来代替字符串,如在UDDI中表达一个Web Service的PortType时,你不应该在某处用字符串“PortType”来表明这是一个Port Type,你应该引用预定义的PortType tModel来表明:
<tModel tModelKey="uuid:e8cf1163-8234-4b35-865f-94a7322e40c3" >
<name> StockQuotePortType</name>
<overviewDoc> <overviewURL> http://location/sample.wsdl <overviewURL> <overviewDoc>
<categoryBag>
<keyedReference tModelKey="uuid:d01987d1-ab2e-3013-9be2-2a66eb99d824" keyName="namespace" keyValue="http://example.com/stockquote/" />
<keyedReference tModelKey="uuid:6e090afa-33e5-36eb-81b7-1ca18373f457" keyName="WSDL type" keyValue="portType" />
</categoryBag>
</tModel>
Web Service与UDDI的关系类似于COM组件服务与Windows注册表的关系,其实它们可以看作是同一个概念的不同发展阶段或不同实现
而UDDI直观的比喻可以是图书馆卡片索引,在我上中学的时候,图书馆没有计算机供读者查询图书信息,只有一柜一柜一橱一橱的索引卡片,记录了图书信息,如作者出版社等,当然最重要的是它在书库里的位置,第几排第几格
分类体系在UDDI中占很大比重,不同的Category如传输协议,命名空间,WSDL Type等,每一个Entity或tModel都可以具有多个分类属性,比如上面的StockQuotePortType tModel,按名称空间来分,它属于http://example.com/stockquote/,按WSDL Type来分,它属于portType;BindingTemplate Entity还具有传输协议的分类,值可以是HTTP或SMTP之类
分类体系在现实生活中随处可见,比如说同一个人,按性别分是mm,按婚否分是未婚,按政治面貌分是刁民;图书馆的索引卡片上也随处可见,按出版社分是三联,按题材分是小说,按风格分是后现代等等
5. UDDI:与WSDL 有关
毕竟都是描述WebService的,还是有部分内容有关系的,于是有了WSDL到UDDI的映射,这样某些工具就可以自动将WebService注册到UDDI中
大体上就是<portType>和<binding>作为tModel映射到UDDI中,<service>映射为<businessService>, <port>映射为<bindingTemplate>
6. JAX-RPC: 首先是Java,其次才是RPC
虽然JAX-RPC不厌其烦的表达自己支持但不依赖SOAP的特性,但支持SOAP之外的消息交换机制究竟目前有没有具体应用,我不知道,每个开发包也从框架上支持任意的消息交换机制,但我见过的应用都是把它们作为SOAP引擎,如果你知道SOAP之外的消息交换机制的具体应用,请告诉我