Welcome

首页 / 软件开发 / 数据结构与算法 / 重新考虑“代码优先”的Web服务

重新考虑“代码优先”的Web服务2010-04-11 infoq Dennis Sosnoski 译者:胡键你开始开发SOAP Web服务了吗?如果是的话,那么你有两种开发风格可选择。第一种被称为“由WSDL开始(start-from-WSDL)”,或是“契约优先(contract first)”,牵涉构建一个WSDL服务描述,并直接关联用于数据交换的XML模式。第二种被称为“由代码开始(start-from-code)”,或是“代码优先(code first)”,牵涉将例子服务代码插入你选择的框架,并由那个代码产生WSDL+模式(schema)。

不论使用哪种开发风格,最终目标都是相同的——你想要你的服务有一个稳定的WSDL+模式定义。当你正工作在一个SOA环境时,这个目标尤其重要。SOA要求服务松耦合,服务间的接口是固定的,且与实现相分离。XML Web服务为实现SOA创建了一个重要的基础,这很大程度上是因为WSDL和模式可以让你以平台中立的方式去指定被一个Web服务使用的XML消息交换。如果WSDL和模式不是稳定的,服务就只能被由服务提供者直接或间接控制的客户端使用——这可不是SOA。

“由代码开始”的问题

“由代码开始”开发Web服务的想法被许多Web服务和SOA领域的权威人士反对。他们觉得“由代码开始”将XML消息结构绑定到了一个特定的实现,这废弃了使用WSDL和模式的整个目的。对于“由代码开始”的最初形式——SOAP编码模式(SOAP encoding scheme)——的确是这样,它被广泛使用以支持rpc/encoded。使用SOAP编码,XML模式直接由服务提供者应用数据结构产生,客户端代码使用这些产生的数据结构副本进行工作。这种数据模型和XML之间自动转换的特性使得rpc/encoded在早期的SOAP中流行——但是它也是这种风格后来被废止的一个重要原因。它意味着,每次你的服务数据结构的改变都会引起模式的改变,客户端将需要使用新的模式重新生成它们的代码。

图1.“由代码开始”的SOAP编码方式

使用SOAP编码除了产生紧耦合,在XML数据表示和模式定义方面它也有一些缺点。SOAP编码是用于对象图的XML序列化算法,以编程语言独立的方式定义。既然它是一个序列化算法,因此就最后产生的XML结构来说没有灵活性——你应用这个算法到你的数据结构上,你所得到的就是用于那些结构的SOAP编码。不幸的是,所使用的序列化规则导致了XML模式对于其他非rpc/encoded消息交换几乎没有任何用处(包括文档校验)。序列化格式同样还导致较差的效率,这是因为引用结构的花销、过多的运行时打印,以及为所有组件使用子元素(而不是在合适的地方使用属性)。

大多数这些问题适用于那些只是在数据结构和XML间序列化的技术。但是“由代码开始”并不意味着必须通过直接序列化来暴露数据模型。使用某种形式的数据绑定,当前的Web服务栈通常都支持数据模型和XML间的灵活转换。使用数据绑定,你可保持对数据的XML表示的控制。那种控制意味着你的模式定义至少可以与实际的数据模型间稍有隔离,并且你可以选择适合你数据的XML表示。使用数据绑定方法,大多数与SOAP编码有关的问题就不再会有了。

“由WSDL开始”的问题

与使用代码工作相比,使用“由WSDL开始”的最大问题就是使用WSDL和模式定义工作的麻烦本性。现代IDE一般都配备了“智能”编辑器和令代码变更容易的强大的重构工具。目前还没有用于WSDL和模式的等价工具。即便是最基础的模式重构,如转换局部定义到全局定义,也不被主流WSDL和模式工具所支持。

因为工具软弱,“由WSDL开始”还需要扎实理解WSDL和模式,这样才能获得良好的效果。如果可供开发者使用的工具没有立足于标准之上,那么最终的WSDL和模式常常是丑陋的大杂烩,它使得服务和数据的结构更加模糊,而不是更清晰。就WSDL部分而言,要有效地理解它还不太困难,但是模式这一部分就不同了。W3C XML模式推荐(“模式”的全称)至少与大多数编程语言一样复杂,要精通它需要花很多工夫。拥有专门架构团队的大型组织可以负担得起雇用或培训模式专家,但是对于更小的组织而言,模式的复杂性是“由WSDL开始”的服务规格的真正障碍。

即使在开发出WSDL和模式定义的初始集合之后,这些“使用的方便性”问题仍然适用。服务综合集合的开发总是一个迭代过程,反复经过规格、原型和测试周期。在每一阶段,功能蹩脚工具所带来的工作不便都会是开发的障碍。

使“由代码开始”起作用

目前,针对“由代码开始”完成服务规格的可用工具已经远远超越令这种开发类型声名狼藉的SOAP编码模型。它们提供了灵活性和可扩展性,使得它能与相当复杂的数据结构一起工作。最重要的是,它们在代码定义的数据结构与相应的XML表示之间增加了一个解耦层。

微软的.NET框架和Sun的JAX-WS 2.0/JAXB 2.0是两个流行的例子。两者都使用内嵌于源代码中的配置信息(在.Net中是属性,在JAX-WS/JAXB中是标注)来控制数据结构与XML间的相互转换。由这种内嵌配置提供的控制是有限的,而且通常等于只需详列出不同于缺省序列化选择的差异。那意味着XML并不必需与数据结构的细节相隔离——例如,如果你给对象增加一个域,它将自动成为XML表示的一部分,除非你显式列出要包含的域——但是它要比一个纯粹的序列化方式要好得多。

图 2.“由代码开始”的.NET和JAX-WS 2.0/JAXB 2.0方式