2002-08-26 10:24
Web服务的(革)创新,第4部分
--Web服务描述语言 (WSDL)
Graham Glass
CEO/首席设计师,The Mind Electric
2001 年 2
月
这篇文章描述的是 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.jar
(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/CurrencyExchangeService.wsdl,您会看到服务的顶级描述。单击这个 WSDL 的 URL 地址,您就会看到在清单 1 中的 WSDL 代码。
请注意,如果访问 XMethods 网站,对于每个 WSDL,您会看到两个版本,其中一个是特别用于 IBM WSDL。这是因为当前 IBM 的 WSDL 工具包中有一个错误,就是不让它处理来自于其他工具包的 WSDL。这个问题不久就会被修复;同时,我使用 XMethods 为创建了一个特为本文服务的版本。
让我们来查看一下 WSDL 文档中的每一部分,从
name:这个属性是可选的,用来说明服务的主要目的。
targetNamespace:这个属性定义了关于服务信息的逻辑命名空间,并且各服务的属性值通常是不同的。这个属性在稍后会作更进一步的讨论。
xmlns:tns:在许多的 WSDL 文件中,这个命名空间并不出现(包括我们的示例),但是很快就会流行起来的。如果出现,则被设置成
targetNamespace 的值。这个属性在稍后会作更进一步的讨论。
xmlns:soap 和
xmlns:xsd:它们是标准命名空间的定义,在以后的 WSDL 文档中被用作指定特定的 SOAP 的信息和数据类型。
xmlns:缺省的
WSDL 文档的命名空间,被设置到 http://schemas.xmlsoap.org/wsdl/ 。所有的 WSDL 标记,像
在
除此之外,服务所使用的任何复杂数据类型必须在一个可选的
让我们详细的看看每一个部分。
一个
一个
在这个示例中,getRate 操作接受了一个 getRateRequest 消息作为它的输入,并返回一个 getRateResponse 消息作为它的输出。
在示例中,
一个
在示例中,通过 Xmethods 网站的 CurrentExchangeBinding 绑定可访问
任何 WSDL 元素可以声明一个可选的
使用 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
CurrencyExchangePortTypeProxy();
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 的 serviceWizard。在尝试调用下面这条命令之前,要确保 \wstk-2.1\bin 在您的PATH路径设置之中:
\demo3> serviceWizard
您应该看到如图 2 中的输出窗口。
图 2:Web 服务生成工具
单击 Next,就会提示您输入类的名字和它的类路径。对于这个示例,其它的地方设置成默认值就可以了。图 3
显示了您如何填写各个字段。
图 3:Web 服务生成工具中的 WSDL 信息
当您单击 Next,会要求您选择希望通过 WSDL 来暴露什么方法。如图 4 所示,按住 Shift
键选择所有的方法。
图 4:通过 WSDL 取出的所选方法
最后,您得到了一个摘要(在图 5 中),并且要按 Finish 来结束这个过程。
图 5: Web 服务创建工具摘要
恭喜您,您已经创建了您的第一个 WSDL 文件!事实上,您实际创建了两个文件:
Weather_Service-interface.wsdl:这个文件包括一个 WSDL 描述的
Weather_Service-impl.wsdl:这个文件定义了 WSDL 描述的
这是很好的一个拆分,因为它减少了实现规范中的接口规范部分的重复。从理论上来说,您可以有很多的 *impl.wsdl 文件对应一个 *interface.wsdl 文件,并且搜索像 UDDI(下一个部分将会讨论)这样的注册表,来寻找与一个特定接口描述对应的一个或多个实现。
一个有趣的问题是:
清单 5:Weather_Service-interface.wsdl
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="IngetTempRequest"/>
message="InsetTempRequest"/>
type="Weather_Service">
namespace="urn:weather-service"
use="encoded"/>
http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:weather-service"
use="encoded"/>
namespace="urn:weather-service"
use="encoded"/>
清单 6:Weather_Service-impl.wsdl
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">
name="Weather_ServicePort">
< BR>
namespace="http://www.weatherservice.com/Weather-interface">
从 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 文件需要在它们的
很可能所有的 WSDL 工具包很快都会采用这种方法。
下一部分
在下一部分中,我们会了解 Web 服务怎样使用 UDDI
(通用描述,发现和集成)来宣传自己,以便让别的 Web 服务使用。我们将用新发布的 IBM UDDI4J 工具包在 UDDI 库里发布和绑定 Web
服务。
参考资料
关于作者
Graham Glass (graham-glass@mindspring.com) 是 The Mind Electric 的创始人、CEO
和首席设计师。该公司设计、构建和颁发许可证给前瞻性的分步式计算基础设施。他相信,因特网的演变将反映出生物思维的演变,而协助人们和企业有效联网的体系结构能帮助人们理解将人脑联结在一起的体系结构。
在创建 The Mind Electric 之前,Graham 是 ObjectSpace 的主席、CTO 和联合发起人之一。该公司总部位于达拉斯,专门从事商家到商家的集成。Graham 还是 ObjectLesson(一家提供前沿技术培训的公司)的创办人。他为 Prentice Hall 撰写了两本有关 UNIX 和 STL 的书籍,并以他对新兴技术的热情和清晰阐述而成为受欢迎的演说家。可通过 graham-glass@mindspring.com 和他联系。