zoukankan      html  css  js  c++  java
  • WSDL:Web 服务描述语言

    这篇文章描述的是 Web 服务描述语言 (WSDL),WSDL是采用 XML语言来描述 Web 服务的
    属性,例如它做什么,它位于哪里和怎样调用它。本文还介绍了 IBM 的 WSDL 工具包,
    此工具包能够从 WSDL 中生成存根,并简化 Web 服务应用的创建过程。

    欢迎进入本专栏的第 4 部分,本专栏重点讲述 Web 服务技术正在革新和创新的方面。
    在第 3 部分(请参阅参考资料)中,我展示了简单对象存取协议 (SOAP) 如何在后台工
    作。在这一部分中,我会解释 WSDL,这个描述 Web 服务的核心属性的标准方法,和一
    些能支持 WSDL 来加速开发过程的工具。


    工具和安装

    我们将在这个部分使用两个新的工具:

    IBM WSTK 2.1:IBM Web 服务工具包 2.1 (请参阅参考资料)包含 Apache SOAP、WSDL
    生成器和通用描述、发现和集成 (UDDI) 客户端。由于在这一系列中我们一直都在使
    用 Apache SOAP 2.0,所以我们继续使用它作为我们的 SOAP 服务器,但是这一部分我
    们将使用 WSTK 的 WSDL 生成器。

    IBM WSDL 1.1 工具包:IBM Web 服务描述语言工具包(请参阅参考资料)生成来自于
    WSDL 的客户端和服务器的存根。它的代码被封装为 wsdl.jar,它使用 WSTK 的 bsf.j
    ar (Bean 脚本框架)和 xalan.jar (XML 样式表单处理器)文件。

    一旦您下载并安装了这些工具,请确保 wsdl.jar、bsf.jar 和 xalan.jar 在您的类路
    径 (CLASSPATH) 下,这样您就可以准备构造你的第一个带有 WSDL 的程序了。


    介绍 WSDL

    Web 服务的一个主要思想,就是未来的应用将由一组应用了网络的服务组合而成。只要
    两个等同的服务使用统一标准和中性的方法在网络上宣传自己,那么从理论上说,一个
    应用程序就可以根据价格或者性能的标准,从两个彼此竞争的服务之中选出一个。除此
    之外,一些服务允许在机器之间复制,因而可以通过把有用的服务复制到本地储存库,
    来提高允许运行在特定的计算机(群)上的应用程序的性能。

    如果您想一想,会发现这很类似于人力劳务市场的运作。提供工作的网站和雇佣公司为
    工人和老板提供中介服务,利用简历和工作描述来加快匹配过程。如果找到了一个好的
    匹配,感兴趣的双方就会尝试磋商可接受的条件。如果达成了协议,工人或者去老板那
    里开工,或者利用因特网和远程通信来作为代替的工作途径。

    Web 服务描述语言是 XML 中相当于简历的等同物 -- 描述 Web 服务做什么,它在哪里
    及如何调用它。想知道它是什么样的,先看看 Xmethods 网站上运行的货币交换服务的
    WSDL(请参阅参考资料)。如果访问过 http://www.xmethods.net/sd_ibm/CurrencyE
    xchangeService.wsdl,您会看到服务的顶级描述。单击这个 WSDL 的 URL 地址,您就
    会看到在清单 1 中的 WSDL 代码。

    请注意,如果访问 XMethods 网站,对于每个 WSDL,您会看到两个版本,其中一个是特
    别用于 IBM WSDL。这是因为当前 IBM 的 WSDL 工具包中有一个错误,就是不让它处理
    来自于其他工具包的 WSDL。这个问题不久就会被修复;同时,我使用 XMethods 为创建
    了一个特为本文服务的版本。

    让我们来查看一下 WSDL 文档中的每一部分,从 <definitions> 段开始。

    <definitions>
    <definitions> 元素包括一个或者多个服务的定义。大多数情况下,一个 WSDL 文件定
    义一个单独的服务。<definitions> 标记后通常紧跟着以下属性的声明:

    name:这个属性是可选的,用来说明服务的主要目的。
    targetNamespace:这个属性定义了关于服务信息的逻辑命名空间,并且各服务的属性值
    通常是不同的。这个属性在稍后会作更进一步的讨论。
    xmlns:tns:在许多的 WSDL 文件中,这个命名空间并不出现(包括我们的示例),但是
    很快就会流行起来的。如果出现,则被设置成 targetNamespace 的值。这个属性在稍后
    会作更进一步的讨论。
    xmlns:soap 和 xmlns:xsd:它们是标准命名空间的定义,在以后的 WSDL 文档中被用作
    指定特定的 SOAP 的信息和数据类型。
    xmlns:缺省的 WSDL 文档的命名空间,被设置到 http://schemas.xmlsoap.org/wsdl/
    。所有的 WSDL 标记,像 <definitions>、<message> 和 <service> 都驻留在这个命
    名空间之内。

    在 <definitions> 之中,有三个概念性的部分:

    <message> 和 <portType>: 服务提供什么操作。
    <binding>: 操作怎样被调用。
    <service>: 服务位于哪里。

    除此之外,服务所使用的任何复杂数据类型必须在一个可选的 <types> 部分里面被定义
    ,而 <types> 部分必须直接放在 <message> 部分之前。因为我们的示例是简单的而且
    只使用原始的参数类型,因而没有 <types> 部分。

    让我们详细的看看每一个部分。

    <message> 和 <portType>
    一个 <message> 对应在调用者和服务之间传递的一条信息。一个规则的有往返的远程方
    法调用有两条消息,一条负责请求,一条负责响应。每一个 <message> 可以没有任何部
    分,或者有多个部分,每个部分都有一个名字和可选的类型。当 WSDL 描述一个对象时
    ,每一个部分映射到一个方法调用的参数上。如果一个方法返回为 void,那么响应就是
    一条空信息。
    一个 <portType> 对应一套单个或多个操作,而一个 <operation> 定义了一个特定的输
    入/输出消息序列。每一个输入/输出的消息属性必须对应前面定义过的 <message> 的
    名称。如果一个操作只指定了输入,则只是单向操作。输出后面紧跟着输入则是请求-响
    应 (solicit-response) 操作,单一的输入是一个通告。当 WSDL 描述一个对象时,每
    一个 <operation> 映射一个方法并且每一个 <portType> 映射一个 Java 接口或类。
    在这个示例中,getRate 操作接受了一个 getRateRequest 消息作为它的输入,并返回
    一个 getRateResponse 消息作为它的输出。

    <binding>
    <binding> 对应于用特定的协议 -- 如 SOAP 或者 CORBA -- 来实现的 <portType> 。
    绑定的类型属性必须对应定义过的 <portType> 的名称。因为 WSDL 是中性的协议,所
    以您可以指定 SOAP、CORBA、DCOM 和其它的标准协议的绑定。如果一个服务支持不止一
    个协议,WSDL 应该对每一个它支持的协议都包含一个 <binding>。
    在示例中,<binding> 部分表明使用标准的 SOAP 编码进行的 RPC 到 HTTP 的通信。也
    请注意 soapAction (在最后的部分描述)在这个示例中的设置是设置成空串,并且服
    务的 URI 被设置成 "urn:xmethods-CurrencyExchange"。

    <service>
    一个<service> 是一个端口集,而 <port> 代表了在特定端点进行特定绑定的可用性。
    端口的绑定属性必须对应于前面定义过的 <binding> 的名称。
    在示例中,通过 Xmethods 网站的 CurrentExchangeBinding 绑定可访问 <service>。

    <documentation>
    任何 WSDL 元素可以声明一个可选的 <documentation> 元素,其中包含人们可读的关于
    那个元素的信息。在示例中,唯一有文档描述的元素是 <service>。对于其他的元素,
    例如独立操作,有文档描述也是很普通的。



    使用 WSDL 来生成客户端存根

    因为 WSDL 包含了对服务接口的完整描述,所以可以使用它来创建能简化服务访问的存
    根。

    IBM WSDL 工具包允许您为 Apache SOAP 创建存根。为了说明这个问题,让我们创建一
    个客户端存根,它允许我们调用在 Xmethods 上建立的货币交换服务。首先,建立一个
    \demo3 目录来存放这部分的所有软件。然后通过使用浏览器的 File, Save as 选项,
    把示例CurrentExchange的 WSDL 文件保存到这个目录下。

    然后通过键入下面的命令来建立客户端存根:
    \demo3> java com.ibm.wsdl.Main -in CurrencyExchangeService.wsdl
    这产生了一个叫做 CurrencyExchangePortTypeProxy.java 的客户端存根类(如清单 2
    所示)。如果得到了 "unable to load JDK compiler" 的消息,您可以忽略掉,因为
    我们将手动编译客户端存根了。

    就象您能看到的,客户端的存根看上去就像我们在前面部分里使用过的代码。客户端程
    序现在能够像常规的 Java 对象那样,使用代理服务类来访问 Web 服务(请参阅清单
    3)。

    清单 3:一个代理服务的客户端类 public class Client1
    {
    public static void main( String[] args ) throws Exception
    {
    CurrencyExchangePortTypeProxy exchange = new CurrencyExchangePortTypePro
    xy();
    float rate = exchange.getRate( "USA", "japan" );
    System.out.println( "rate = " + rate );
    }
    }

    如果您编译并运行这些文件,您应该能够看到在图 1 里的输出。

    图 1:来自于 CurrencyExchangePortTypeProxy.java 的输出



    生成 WSDL

    大多数厂商的工具包包括某些从一个组件中自动生成 WSDL 的方法,其中包括 IBM WSTK
    和 Microsoft .NET studio。为了说明 WSTK 如何允许从一个服务生成 WSDL,我将使
    用在清单 4 中的天气服务。

    清单 4:从一个组件中生成 WSDL public class Weather
    {
    public float getTemp( String zipcode )
    {
    System.out.println( "getTemp( " + zipcode + " )" );
    return 56;
    }
    public void setTemp( String zipcode, float temp )
    {
    System.out.println( "setTemp( " + zipcode + ", " + temp + " )" );
    }
    }

    为了给这个类创建 WSDL,首先要编译它,然后在 \demo3 目录里启动 WSTK 的 servic
    eWizard。在尝试调用下面这条命令之前,要确保 \wstk-2.1\bin 在您的PATH路径设置
    之中:
    \demo3> serviceWizard
    您应该看到如图 2 中的输出窗口。

    图 2:Web 服务生成工具

    单击 Next,就会提示您输入类的名字和它的类路径。对于这个示例,其它的地方设置成
    默认值就可以了。图 3 显示了您如何填写各个字段。

    图 3:Web 服务生成工具中的 WSDL 信息

    当您单击 Next,会要求您选择希望通过 WSDL 来暴露什么方法。如图 4 所示,按住 S
    hift 键选择所有的方法。

    图 4:通过 WSDL 取出的所选方法

    最后,您得到了一个摘要(在图 5 中),并且要按 Finish 来结束这个过程。

    图 5: Web 服务创建工具摘要

    恭喜您,您已经创建了您的第一个 WSDL 文件!事实上,您实际创建了两个文件:
    Weather_Service-interface.wsdl:这个文件包括一个 WSDL 描述的 <message>、<por
    tType> 和 <binding> 部分,它描述了 Web 服务的接口(请参阅清单 5)。
    Weather_Service-impl.wsdl:这个文件定义了 WSDL 描述的 <service> 部分,然后导
    入 Weather_Service-interface.wsdl(请参阅清单 6)。

    这是很好的一个拆分,因为它减少了实现规范中的接口规范部分的重复。从理论上来说
    ,您可以有很多的 *impl.wsdl 文件对应一个 *interface.wsdl 文件,并且搜索像 UD
    DI(下一个部分将会讨论)这样的注册表,来寻找与一个特定接口描述对应的一个或多
    个实现。

    一个有趣的问题是:<binding> 部分真的是属于 WSDL 接口文件?还是属于实现文件?
    您可以认为它是属于实现文件,因为它是专门用于特别的绑定,例如 SOAP 或 CORBA。
    我们只好等着看是否会有一个未来的标准来为此设定规范。

    清单 5:Weather_Service-interface.wsdl
    <?xml version="1.0" encoding="UTF-8"?>
    <definitions name="Weather_Service-interface"
    targetNamespace="http://www.weatherservice.com/Weather-interface
    xmlns="http://schemas.xmlsoap.org/wsdl/
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/
    xmlns:tns="http://www.weatherservice.com/Weather
    xmlns:xsd="http://www.w3.org/1999/XMLSchema>
    <message
    name="IngetTempRequest">
    <part name="meth1_inType1"
    type="xsd:string"/>
    </message>
    <message
    name="OutgetTempResponse">
    <part name="meth1_outType"
    type="xsd:float"/>
    </message>
    <message
    name="InsetTempRequest">
    <part name="meth2_inType1"
    type="xsd:string"/>
    <part name="meth2_inType2"
    type="xsd:float"/>
    </message>
    <portType
    name="Weather_Service">
    <operation name="getTemp">
    <input
    message="IngetTempRequest"/>
    <output
    message="OutgetTempResponse"/>
    </operation>
    <operation
    name="setTemp">
    <input
    message="InsetTempRequest"/>
    </operation>
    </portType>
    <binding
    name="Weather_ServiceBinding"
    type="Weather_Service">
    <soap:binding style="rpc"
    transport="http://schemas.xmlsoap.org/soap/http/>
    <operation
    name="getTemp">
    <soap:operation
    soapAction="urn:weather-service"/>
    <input>
    <soap:body
    encodingStyle="http://schemas.xmlsoap.org/soap/encoding/
    namespace="urn:weather-service"
    use="encoded"/>
    </input>
    <output>
    <soap:body
    encodingStyle="http://schemas.xmlsoap.org/soap/encoding/
    namespace="urn:weather-service"
    use="encoded"/>
    </output>
    </operation>
    <operation
    name="setTemp">
    <soap:operation
    soapAction="urn:weather-service"/>
    <input>
    <soap:body
    encodingStyle="http://schemas.xmlsoap.org/soap/encoding/
    namespace="urn:weather-service" use="encoded"/>
    </input>
    </operation>
    </binding>
    </definitions>

    清单 6:Weather_Service-impl.wsdl
    <?xml version="1.0" encoding="UTF-8"?>
    <definitions name="Weather_Service"
    targetNamespace="http://www.weatherservice.com/Weather
    xmlns="http://schemas.xmlsoap.org/wsdl/
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/
    xmlns:tns="http://www.weatherservice.com/Weather
    xmlns:xsd="http://www.w3.org/1999/XMLSchema>
    <service
    name="Weather_Service">
    <documentation>IBM WSTK 2.0 generated service definition file</documentati
    on>
    <port
    binding="Weather_ServiceBinding"
    name="Weather_ServicePort">
    <soap:address
    location="http://localhost:8080/soap/servlet/rpcrouter//>
    </port>
    </service><import
    location="http://localhost:8080/wsdl/Weather_Service-interface.wsdl
    namespace="http://www.weatherservice.com/Weather-interface>
    </import>
    </definitions>



    从 WSTK WSDL 文件中生成存根

    从 WSTK WSDL 文件来创建存根显得有一点复杂,由于 Weather_Service.impl 之中的导
    入说明,使得 WSDL 存根产生器需到接口文件的位置执行HTTP Get。在这个示例中,它
    是 http://localhost:8080/wsdl/Weather_Service-interface.wsdl。确保Tomcat 能
    够为这个文件提供服务,在 Tomcat 的根文件夹 $TOMCAT_HOME\webapps\ROOT 中创建一
    个目录 \wsdl,并把所有的 .wsdl 文件复制到这个目录中。然后,假定 tomcat 正运行
    在 \demo3 目录下,在 \demo3 目录下键入以下命令:
    \demo3> java com.ibm.wsdl.Main -in Weather_Service-impl.wsdl
    Tomcat 将会从自己的 \wsdl 目录下提供 Weather_Service-interface.wsdl 文件,而
    您应该会在 \demo3 目录下得到一个名叫 Weather_ServiceProxy.java 的存根类。清单
    7 是一个测试客户端程序,它可以访问在您本地的 Tomcat 服务器上运行的天气服务:

    清单 7:天气 Web 服务的测试代码 public class Client2
    {
    public static void main( String[] args ) throws Exception
    {
    Weather_ServiceProxy weather = new Weather_ServiceProxy();
    float temp = weather.getTemp( "75248" );
    System.out.println( "temp = " + temp );
    weather.setTemp( "75248", 84 );
    }
    }

    想要运行这个程序,编译 \demo3 目录下的所有 Java 文件,然后使用 Apache 配置屏
    ,用 URN urn:weather-service 来部署天气服务,然后执行客户端程序。图 6 显示了
    当您填完所有的字段后,配置屏看上去的样子:

    图 6:运行 Web 服务

    当您运行程序时,客户端应该显示 getTemp() 的调用返回,而 Tomcat 窗口将会显示出
    收到的 setTemp() 调用。


    目标命名空间

    由于 WSDL 文件能够导入其它的 WSDL 文件,因此总有可能发生名字冲突的时候。所以
    ,最晚拿到的 WSDL 文件需要在它们的 <definitions> 部分里面定义 targetNamespace
    和 xml:tns 的属性,在那里 targetNamespace 被设成对应于特定的 WSDL(通常是原
    始的 WSDL 文件的名称)的一个唯一 URL。完成此功能的 WSDL 生成器利用 tns: 对部
    分与部分之间的引用做范围界定,来防止相同名字冲突。举一个示例,在清单 8 里,操
    作声明使用 tns: 前缀,明确地把它使用的消息的范围界定在一个特定的 WSDL 文件中

    图 8:使用 tns: 前缀
    <portType name = "CurrencyExchangePortType">
    <operation name = "getRate">
    <input message = "tns:getRateRequest" name = "getRate"/>
    <output message = "tns:getRateResponse" name = "getRateResponse"/>
    </operation>
    </portType>

    很可能所有的 WSDL 工具包很快都会采用这种方法。



    下一部分

    在下一部分中,我们会了解 Web 服务怎样使用 UDDI (通用描述,发现和集成)来宣传
    自己,以便让别的 Web 服务使用。我们将用新发布的 IBM UDDI4J 工具包在 UDDI 库里
    发布和绑定 Web 服务。


    参考资料
    在第 1 部分中,Graham 详细介绍了构建 Web 服务应用以实现对等分布式网络的优势及
    其面临的挑战。
    在第 2 部分中,Graham 提供了如何开发 Web 服务的循序渐进的解释,其中包括您需要
    什么工具,如何安装它们,如何编写代码以及如何配置服务。
    在这个专栏的第 3 部分中,Graham 详细介绍了 SOAP 在线上交换信息的行为并解释了
    它是怎样工作的。
    请回顾第一个版本的 WSDL 1.0 规范。
    请从 alphaWorks 下载 IBM 的 WSDL 工具包。
    请从 alphaWorks 下载 IBM 的 Web 服务工具包。
    Xmethods.net 有一个提供公共的 Web 服务的目录,这篇文章用到了其中的一个服务。


    关于作者
    Graham Glass (graham-glass@mindspring.com) 是 The Mind Electric 的创始人、CE
    O 和首席设计师。该公司设计、构建和颁发许可证给前瞻性的分步式计算基础设施。他
    相信,因特网的演变将反映出生物思维的演变,而协助人们和企业有效联网的体系结构
    能帮助人们理解将人脑联结在一起的体系结构。
    在创建 The Mind Electric 之前,Graham 是 ObjectSpace 的主席、CTO 和联合发起人
    之一。该公司总部位于达拉斯,专门从事商家到商家的集成。Graham 还是 ObjectLess
    on(一家提供前沿技术培训的公司)的创办人。他为 Prentice Hall 撰写了两本有关
    UNIX 和 STL 的书籍,并以他对新兴技术的热情和清晰阐述而成为受欢迎的演说家。可
    通过 graham-glass@mindspring.com 和他联系。
  • 相关阅读:
    Mininet学习指南
    Docker and OverlayFS in practice
    (OK) dnf——install docker on Fedora23
    Running Docker Swarm inside LXC
    ERROR——running docker in CORE on Fedora23
    (OK) dnf
    (OK) simply running CORE & docker on Fedora 23
    北京大学互联网信息工程研发中心(深圳)
    nload
    (OK) CORE
  • 原文地址:https://www.cnblogs.com/cxd4321/p/989519.html
Copyright © 2011-2022 走看看