Web服务搜索与执行引擎(七)——重温WSDL与SOAP
接下来的几篇文章是让我很兴奋的,我想大家应该也很兴奋,因为接下来要阐述的就是我们最核心的思想了,希望能够带给大家一个激动人心的Web服务之旅。
WEB服务搜索与执行过程的一个核心东西就是Web 服务描述语言(WSDL),其次还有一个重要的东西就是SOAP消息,这两也就是在谈到WEB服务时必不可少的,同时它俩也是标准协议来的。所以接下来很有必要对先对WSDL文档跟SOAP消息再作一个系统的描述,然后再阐述传统的方法里是如何在客户端调用一个远程WEB服务(或是异构的)的,而我们团队是如何处理动态调用异构平台下的WEB服务的。
我想在这文章里先回顾一下有关WSDL文档跟SOAP消息的有关知识,但这不是一篇详细介绍WSDL文档规范的文章,有关这方面的资料网上有很多大家可以结合着看。如果说大家已经在这方面很熟悉了,可以跳过这部分,等我在接下来的文章里写服务的解析时在关注也行,不过下面将介绍的这两种标准协议不是就协议说协议,而是结合了后面将要阐述的系统的核心组件——服务的动态执行做铺垫,所以建议大家还是看看。
有关WSDL与SOAP
其实现在再看WSDL文档,第一感受马上想到的就是它是一个XML文档,也就是因为它是一个XML文档,一个用“全世界人”都能“看懂”的语言写成的文档,无论到了哪个“生活环境”下,人们都能够“接受”它,”利用”它。对应到WEB服务的世界里,为能够平台无关和实现独立地访问Web服务,软件业赞同将一部分技术作为标准。最根本的就是刚才说到的“全球人都能看得懂,听得懂的语言”: XML——一个默认的数据格式,被用于Web服务环境中的所有层次。另外两个协议他们的传输其实也是一个XML文档:
l SOAP——默认的包装和交换消息的协议。第一次介绍时,它是Simple Object Access Protocol的首字母缩写。现在,人们认识到以前对SOAP的理解是有误的:SOAP并不只是为了访问对象。另外,它也并不简单。
l WSDL——描述Web服务的语言。尽管基于XML并能为人所理解,但是WSDL主要是为机器使用的,使客户程序(“生活环境”)能读并理解(“接受”它,”利用”)它。
下图展示了所有的技术是如何在一个环境中工作的:
这里,Provider是提供服务的应用组件,Requester是使用服务的客户程序。很多其他的技术可能会参加到交互中,但是上图展示的是Web服务环境中必不可少的核心组件。
将以上概念对应到我们的项目:
提供服务的应用组件①:Provider,它可能是.net平台下的C#程序,也可
能是我们在Java平台上所使用的XFire——一个免费的、开源的SOAP框架。然而,最终我们是要屏蔽掉后台这些正在工作的复杂组件,所以说提供服务的组件肯定是要把他们想要对外开放的某些操作,以服务接口的形式发布成WSDL文档描述的Web服务。所以WSDL文档是一个“国际外交官”,每个国家都供认的外交官。
使用服务的客户程序②:Requester,在这里指的是我们系统搜索引擎与执行引擎模块,为什么搜索引擎也算呢,因为用户选择了要消费哪个Web服务后系统首先要跟“国际外交官”WSDL文档交流了解服务的具体情况,而执行时是很明显的。
①<---④SOAP③----->②之间的交互显然最重要的是WSDL文档了,因为这是它们的契约。或许大家已经发现了中间写上了SOAP,请大家注意,我们团队的解决方案关键点就在这里了:客户端程序②以SOAP消息的形式发送服务请求到服务端程序①。或许大家也已经发现了,对我们系统的构建,又出现了一个重要的:SOAP消息。无论是客户端服务的请求还是服务端对请求者的响应最终都是要依靠SOAP消息,然后绑定到HTTP消息来进行传输。
看完上面的描述再来看看最标准的WSDL的解释吧:Web 服务描述语言(WSDL)是用于描述 Web 服务的一种 XML 语言,它将 Web 服务描述为一组对消息 WSDL 服务描述包含对一组操作和消息的一个抽象定义,绑定到这些操作和消息的一个具体协议,和这个绑定的一个网络端点规范。进行操作的网络端点。一个
WSDL文档要点
我想上面说了这么多有关WSDL文档,大家一定想要再次看看WSDL文档有有关内容了,下面我将展现给大家的是来自我们团队指导老师,那俊老师的有关WSDL 文档的个人总结:
一、WSDL文档的基本结构
WSDL文档可以分为两部分:顶部分由抽象定义组成;底部分则由具体描述组成。
1. 抽象部分
抽象部分以独立于平台和语言的方式定义SOAP消息,它们并不包含任何随机器或语言而变的元素。这就定义了一系列服务,截然不同的网站都可以实现。
抽象定义:
•Types:独立于机器和语言的类型定义;
•Messages:包括函数参数(输入与输出分开)或文档描述;
•PortTypes:引用消息部分中消息定义来描述函数签名(操作名、输入参数、输出参数)。
2. 具体部分
随网站而异的东西如序列化便归入底部分,因为它包含具体的定义。
具体定义:
•Bindings:PortTypes部分的每一操作在此绑定实现;
•Services:确定每一绑定的端口地址。
二、WSDL各部分详细分析
WSDL文档的生成与接口中的操作一一对应,下面结合依据接口IGreetService发布的Web服务的WSDL文档队标签进行详细分析。
表1 接口IGreetService结构
publicinterface IGreetService {
public String GreetMe();
}
1. Types部分
<wsdl:types>元素对应的是接口中所有操作的输入和输出的数据类型,即,将每个方法的输入参数列表中的所有参数组合为一种数据类型,将其输出参数也定义为一种数据类型。
表2 WSDL文档中的Types部分内容
- <wsdl:types>
<xsd:schema xmlns:xsd=http://www.w3.org/2001/XMLSchema
attributeFormDefault="qualified" elementFormDefault="qualified"
targetNamespace="http://localhost:8080/GreetService/services/Greeting">
<xsd:element name="GreetMe">
<xsd:complexType/>
</xsd:element>
<xsd:element name="GreetMeResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="out"
nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
<wsdl:types>中包含很多独立的<xsd:element>元素,每一个<xsd:element>对应上述一种数据类型。
这里有两个element:
• GreetMe对应方法GreetMe的输入参数,而方法GreetMe输入参数为空,所以其中包含一个空的复杂类型声明<xsd:complexType>。
• GreetMeResponse对应方法GreetMe的输出参数,由于方法GreetMe的输出为一个字符串,所以,其中包含一个<xsd:complexType>标签,其中包含一个字符串类型(xsd:string)的参数。
其中以xsd开头的部分不是WSDL范畴的内容,需要查看编写xsd的规范才能了解。
2. Messages部分
Messages部分分别列举出接口中所有操作的输入或者输出,每一个<wsdl:message>元素对应一个操作的输入,或者对应一个输出。
表3 WSDL文档中Messages部分内容
<wsdl:message name="GreetMeResponse">
<wsdl:part name="parameters" element="tns:GreetMeResponse"/>
</wsdl:message>
<wsdl:message name="GreetMeRequest">
<wsdl:part name="parameters" element="tns:GreetMe"/>
</wsdl:message>
在该WSDL文档中有两个<wsdl:message>元素:
• GreetMeResponse对应GreetMe方法的输出,也是该方法的相应消息。其中<wsdl:part>元素描述出了该输出的数据类型为<wsdl:types>中定义的GreetMeRespose类型。
• GreetMeRequest对应GreetMe方法的输入,也是该方法的请求消息。其中<wsdl:part>元素描述出了该输入的数据类型为<wsdl:types>中定义的GreetMe类型。
本来一个<wsdl:message>元素中可以有多个<wsdl:part>元素,但是,这一工作可以在<wsdl:types>元素中得到简化,因此,通常每个<wsdl:message>元素中只有一个<wsdl:part>元素。
3. PortTypes部分
PortTypes部分以操作为单位,列出了接口中的所有操作的名字、输入和输出消息格式。<wsdl:portType>元素对应该接口的所有操作的集合。
表4 WSDL文档中PortTypes部分内容
<wsdl:portType name="GreetingPortType">
<wsdl:operation name="GreetMe">
<wsdl:input name="GreetMeRequest" message="tns:GreetMeRequest"/>
<wsdl:output name="GreetMeResponse" message="tns:GreetMeResponse"/>
</wsdl:operation>
</wsdl:portType>
在<wsdl:portType>元素中,有一个或多个<wsdl:operation>元素,接口中的每一个操作对应一个<wsdl:operation>元素,其name属性对应操作的名字。这里,接口中只有一个操作GreetMe,因此,name属性值为GreetMe。
在每一个<wsdl:operation>元素中,列出了其请求消息和相应消息的消息格式,分别用<wsdl:input>和<wsdl:output>表示,其message属性则引用由<wsdl:message>元素定义的一种消息格式。
WSDL有四种端点支持的传输元语(transmission primitives):
•单向(One-Way):端点只接收一个消息;
表5 单向PortType样式
<wsdl:operation name="nmtoken">
<wsdl:input name="nmtoken"? message="qname"/>
</wsdl:operation>
• 请求-响应(Request-response):端点接收一个消息,并发送一个相应的消息;
表6 请求-响应PortType样式
<wsdl:operation name="nmtoken" parameterOrder="nmtokens">
<wsdl:input name="nmtoken"? message="qname"/>
<wsdl:output name="nmtoken"? message="qname"/>
<wsdl:fault name="nmtoken" message="qname"/>*
</wsdl:operation>
• 征求-响应(Solicit-response):端点发出一个消息,并接收一个相应的消息;
表7 征求-响应PortType样式
<wsdl:operation name="nmtoken" parameterOrder="nmtokens">
<wsdl:output name="nmtoken"? message="qname"/>
<wsdl:input name="nmtoken"? message="qname"/>
<wsdl:fault name="nmtoken" message="qname"/>*
</wsdl:operation>
• 通知(Notification):端点发送一个消息。
表8 通知PortType样式
<wsdl:operation name="nmtoken">
<wsdl:output name="nmtoken"? message="qname"/>
</wsdl:operation>
4. Bingdings部分
Bingdings部分为PortTypes部分中定义的操作和消息定义消息格式和协议的细节,一个给定的PortType可以对应任意多个Binding。
表9 WSDL文档中Bindings部分内容
<wsdl:binding name="GreetingHttpBinding" type="tns:GreetingPortType">
<wsdlsoap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GreetMe">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="GreetMeRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="GreetMeResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
在<wsdl:binding>元素中,通过type属性使该元素关联到一个特定的<wsdl:portType>元素。每一个<wsdl:binding>元素都需要指定其绑定协议,但是不需要制定具体的地址信息。
绑定有三种方式:
• SOAP绑定;
• HTTP GET和POST绑定;
•l MIME绑定。
5. Services部分
Services部分是一组端口(port)的集合。每一个port通过对绑定指定一个单独的地址来定义一个独立的端点(endpoint)。
表10 WSDL文档中Services部分内容
<wsdl:service name="Greeting">
<wsdl:port name="GreetingHttpPort" binding="tns:GreetingHttpBinding">
<wsdlsoap:address
location="http://localhost:8080/GreetService/services/Greeting"/>
</wsdl:port>
</wsdl:service>
每一个<wsdl:service>元素中可以有一个或多个<wsdl:port>元素。每一个<wsdl:port>元素不能指定多个地址,且不能指定除地址外的其他信息。这些port不能相互通信。如果几个port共享同一个portType,但使用了不同的绑定或地址,则这些是port是可以相互替换的。
这里只发布了一个端口,它采用了GreetingHttpBingding协议,处在http://localhost:8080/GreetService/services/Greeting(因为是用tomcat发布的)。
上面那些就是我们那俊老师的有关WSDL 文档的个人总结,我想看完了上面的详细描述后,对WSDL文档的“整棵树”细到“枝叶“都了解得很透彻了。要理解我们团队的解决方案首先必须对上面内容相当熟悉。
初看SOAP
接下来我想对SOAP消息再做一个回顾,上面说明的WSDL规范其实就好比是我们国家的法侓,它规定了公民(好比是SOAP消息)应该要怎么行使个*力以及履行个人义务等,即具有指导性的意义。
首先SOAP是一个简单的协议,制定这样的协议的基本出发点就是分布式架构中需要交换信息。而且,在一个负荷可能很重的系统中,该协议是轻量级的,只需要很少的开销,它还允许所有操作都在HTTP 上进行,这样就绕过了防火墙等棘手问题,并且可以避免使用传统的监听各种端口号的套接字来进行信息的交互了。
SOAP 规范中有三个基本的组成部分:SOAP 封装(envelope),一套编码规则,一种在请求和响应之间交互的方式。我们都知道有一个比较经典的比喻,我们把SOAP 消息想像成一封实际的信,这些包含奇怪东西的信封也带有邮资标记,上面也写满了地址。这一比喻有助于使“封装”这样的概念更好理解。
面对项目需求,我们是这样思考SOAP应该如何调用的。
请求消息都是根据服务提供方的服务接口先生成一个SOAP请求,然后由Web容器(Tomcat)生成HTTP请求,在请求当中封装所要调用的方法,以及方法调用时的参数。客户端服务调用代码要完成的任务,也就是使用实现所提供的接口,来声明调用方所需要的方法名及参数,然后由实现根据用户的输入来组合生成一个SOAP请求消息。
这个过程可以这样来描述,首先获取用户输入,然后把输入变成实现所要求的存储格式,然后再把该格式变成SOAP请求。一般情况下,我们需要手工完成到第二步,但是,这个过程显然是可以把他自动化的,自动化的效果就是用户不再需要书写这部分的代码,减少工作量和降低出错几率。自动化的过程就需要WSDL的参与,他提供了服务方服务的描述,调用方根据这个描述,就可以知道服务所需要的参数个数,然后向用户索取。得到输入以后,实现可以根据WSDL的要求来把输入转换成特定的存储格式,或者直接生成最后的SOAP请求。
在前面的WSDL各部分详细分析中我们知道,对于每个服务,WSDL需要描述两部分的内容,一是接口,二是实现。接口描述了服务的格式,例如服务名,服务参数,服务结果。服务实现则描述了,用户所对应提供的输入如何转换成符合某一实现协议的形式,一般情况下,我们使用SOAP作为实现协议,那么客户端在分析了WSDL文件以后,将会把用户的输入转换成我们已经看到过的SOAP请求,之后的过程就与之前的完全一样。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lin_bei/archive/2007/04/19/1571017.aspx
上一篇: Properties 类读取配置文件
下一篇: 表分区