接下来的几篇文章是让我很兴奋的,我想大家应该也很兴奋,因为接下来要阐述的就是我们最核心的思想了,希望能够带给大家一个激动人心的Web服务之旅。 WEB服务搜索与执行过程的一个核心东西就是Web 服务描述语言(WSDL),其次还有一个重要的东西就是SOAP消息,这两也就是在谈到WEB服务时必不可少的,同时它俩也是标准协议来的。所以接下来很有必要对先对WSDL文档跟SOAP消息再作一个系统的描述,然后再阐述传统的方法里是如何在客户端调用一个远程WEB服务(或是异构的)的,而我们团队是如何处理动态调用异构平台下的WEB服务的。我想在这文章里先回顾一下有关WSDL文档跟SOAP消息的有关知识,但这不是一篇详细介绍WSDL文档规范的文章,有关这方面的资料网上有很多大家可以结合着看。如果说大家已经在这方面很熟悉了,可以跳过这部分,等我在接下来的文章里写服务的解析时在关注也行,不过下面将介绍的这两种标准协议不是就协议说协议,而是结合了后面将要阐述的系统的核心组件——服务的动态执行做铺垫,所以建议大家还是看看。有关WSDL与SOAP其实现在再看WSDL文档,第一感受马上想到的就是它是一个XML文档,也就是因为它是一个XML文档,一个用“全世界人”都能“看懂”的语言写成的文档,无论到了哪个“生活环境”下,人们都能够“接受”它,”利用”它。对应到WEB服务的世界里,为能够平台无关和实现独立地访问Web服务,软件业赞同将一部分技术作为标准。最根本的就是刚才说到的“全球人都能看得懂,听得懂的语言”: XML——一个默认的数据格式,被用于Web服务环境中的所有层次。另外两个协议他们的传输其实也是一个XML文档:
看完上面的描述再来看看最标准的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 规范中有三个基本的组成部分:SOAP 封装(envelope),一套编码规则,一种在请求和响应之间交互的方式。我们都知道有一个比较经典的比喻,我们把SOAP 消息想像成一封实际的信,这些包含奇怪东西的信封也带有邮资标记,上面也写满了地址。这一比喻有助于使“封装”这样的概念更好理解。 面对项目需求,我们是这样思考SOAP应该如何调用的。请求消息都是根据服务提供方的服务接口先生成一个SOAP请求,然后由Web容器(Tomcat)生成HTTP请求,在请求当中封装所要调用的方法,以及方法调用时的参数。客户端服务调用代码要完成的任务,也就是使用实现所提供的接口,来声明调用方所需要的方法名及参数,然后由实现根据用户的输入来组合生成一个SOAP请求消息。
这个过程可以这样来描述,首先获取用户输入,然后把输入变成实现所要求的存储格式,然后再把该格式变成SOAP请求。一般情况下,我们需要手工完成到第二步,但是,这个过程显然是可以把他自动化的,自动化的效果就是用户不再需要书写这部分的代码,减少工作量和降低出错几率。自动化的过程就需要WSDL的参与,他提供了服务方服务的描述,调用方根据这个描述,就可以知道服务所需要的参数个数,然后向用户索取。得到输入以后,实现可以根据WSDL的要求来把输入转换成特定的存储格式,或者直接生成最后的SOAP请求。
在前面的WSDL各部分详细分析中我们知道,对于每个服务,WSDL需要描述两部分的内容,一是接口,二是实现。接口描述了服务的格式,例如服务名,服务参数,服务结果。服务实现则描述了,用户所对应提供的输入如何转换成符合某一实现协议的形式,一般情况下,我们使用SOAP作为实现协议,那么客户端在分析了WSDL文件以后,将会把用户的输入转换成我们已经看到过的SOAP请求,之后的过程就与之前的完全一样。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1571017