虽然发布的服务很简单,Axis帮我们生成的WSDL文档看起来却是比较复杂的,之所以这样的主要原因是WSDL要考虑到兼容各种实现和具有可扩展性,这就像我们使用一些框架做开发会使代码总量增加,而好处是使逻辑更加清晰。这篇帖子的上半部分介绍了WSDL里常用到的名称空间,现在就来说说WSDL里各元素的含义。
一个WSDL文档里一般包含<types>、<message>、<portType>、<binding>和<service>这几个元素,其中<types>、<message>和<portType>可以看作抽象的接口定义,而<binding>和<service>是具体的实现,注:有些时候也把<binding>看作接口的一部分。你也许看过一些WSDL把这两部分分开写在两个xml文件里,并在其中一个文件里引入(import)另一个的情况,这也是为什么要区分接口和实现的原因之一。在现实世界里,接口部分很可能是由某个组织(例如某行业协会)制定好的,该组织的成员在发布自己的Web服务时都要引入它,从而达到统一标准的目的。
<types>标签用来定义Web服务里用到的,XML Schema定义的数据类型以外的自定义数据类型,对于我们自定义的类(Book),会对应到一个<complexType>,其中用<element>元素指定每个参数的类型。JAX-RPC规范中规定了Java语言的数据类型到XML Schema数据类型的映射,例如int<->xsd:int、java.lang.String<->xsd:string等等,还有数组的映射方式。
<message>标签定义Web服务里的消息,最常见的就是请求和响应消息。<message>中可以有<part>元素,它对应Java类中各个方法的参数或返回值,例如addBook()方法有一个Book类型的参数,则在WSDL中会有<part name="book" type="tns1:Book"/>的描述。
<portType>标签表示一个服务的类型,就是接口的意思了。WSDL里有些概念很容易混淆,比如port和service的区别,我把service理解为有一个具体URL的服务,而port代表某一地址,portType是service的抽象,不知道对不对。我们看一个WSDL文档,一般就该先找<portType>元素,看看这个WSDL代表的Web服务里都有哪些方法,它们的参数和返回值是什么。这些方法是在<portType>里用<operation>元素表示的,<operation>可以有<input>和<output>子元素,表示方法的输入和输出。注意,方法可以是只有输入或只有输出的。
<binding>元素将portType与具体的传输协议绑定。现在,绝大多数都是与SOAP绑定的,对每一个方法的输入和输出,都要指定SOAP的表示方法。JAX-RPC规范规定,SOAP绑定可以有rpc和document两种类型,分别表示远程过程调用和基于消息的方式。use属性可以是encoded或literal,对于前者要支持rpc的方式,对于后者要支持rpc和document的方式,它们使得SOAP消息的格式有所区别,但我还没有仔细研究,你可以参考一下JAX-RPC 1.1版本的6.3-6.4节。又想起另外一个问题,SOAP和HTTP的关系是怎样的,绑定到SOAP就等于绑定到HTTP了吗,应该不是,那么在哪里指定Web服务绑定的应用层协议(HTTP、SMTP等等)呢?(Update: 由transport属性指定应用层协议)
最后,<service>元素通过<port>子元素把服务联系到一个具体的URL,更确切点,应该是把一个已绑定的portType联系到某个URL,这样就知道该把SOAP消息发给哪个服务器了。
我觉得之所以应该花比较多的时间理解WSDL,因为WSDL在整个Web服务中扮演了十分核心的角色,它是对Web服务的一个比较完整的语法上的描述,同时,它还与XML、SOAP以及UDDI都有着非常密切的联系,因此对于我们更好的认识Web服务体系结构是很重要的。虽然现在的Web服务开发工具都能自动进行Java<->WSDL的转换,但理解WSDL对于Web服务的不论是设计、开发还是修改调试都是必要的。
参考资料: