内容


Web 服务的体系结构和最佳实践

Comments

© Copyright International Business Machines Corporation 2003. All rights reserved.

本文是从 Kyle Brown、Gary Craig、David Pitt、Russell Stinehour、Mark Weitzel、Jim Amsden、Peter M. Jakab 和 Daniel Berg 合著的新书 Enterprise Java Programming with IBM WebSphere Second Edition的节选,将由 Addison-Wesley 出版社在2003年11月出版

引言

在本章中我们将会讨论一些由Web服务引起的体系结构上的挑战,研究如何使用(和不使用)Web服务,并了解一些在应用 Web 服务来解决艰难的体系结构问题时采用的最佳实践。Web 服务是我们的体系结构路标上的最后一个部分。在本章中,您将会看到在 WebSphere 中 Web 服务通常如何使用无状态的会话 Bean 作为其组件实现。在我们的路标中,Web 服务的位置如下图所示(图34.1)。

图34.1. 体系结构路标
体系结构路标
体系结构路标

一些Web服务能做和不能做的事

在采用任何一种新技术时都会存在一条常见的感情变化曲线。首先,当您开始听到一种技术的风声时,您就开始考虑它可能对解决您的特定问题有用,有正面的倾向看法。当您知道更多时,您的激情增加,也许短期的概念性验证是成功的,并导致您用双脚跳起来,并在新的大项目中采用新技术。然后,这种技术的状态的现实表现出来了,并且您开始发现了这种新技术的局限性。此时,您可能能够艰难地前进并使项目取得成功,即便技术存在局限性,或项目可能失败,让您感到失去希望和梦想破灭。古老的格言“所有的万能药都变成毒药”适用于大多数新技术,并且它对于 Web 服务同样适用。

在过去的两、三年里,Web 服务开始应用于实际的应用程序,从那时起,一系列关于 Web 服务何时实用、何时不实用的基本肯定或基本否定的情形就出现了。接下来,我们将会讨论这方面的一些基本原则,并讨论各种情形,无视这一点已经使项目出现差错。

原则:争取不要在逻辑应用层之间使用基于 XML 的 Web 服务。

当 Web 服务被用来补充其他 J2EE 技术,而不是替代它们时,它工作得最好。例如,一种极好的使用 Web 服务的方法就是,从应用程序的客户端出发,通过全球的因特网,连接到 WebSphere Application Server 中用 EJB 编写的业务逻辑。这里您得到了您的控制器和应用程序域层之间的一种良好的、清楚的隔离。这是您将会使用 EJB 的同一个地方,因此,如果您将 Web 服务作为另一个对象分布机制来考虑,那么您就会看到为什么这将是合适的。在 HTTP 之上的 SOAP 将会在 IIOP 之上 RMI 无效的地方发挥作用,因而,这将使得基于 XML 的 Web 服务能够补充现有的 EJB。

然而,人们经常在这一点上犯错误的地方是假定,如果这在一对层之间有效,那么它将会在另一对层之间同样有效。例如,一个我们熟得不能再熟了的常见反模式(anti-pattern)是这样的一种设计:一个持久性层被包装在一个 XML API 内,然后将它放在与需要激活这个持久层的业务逻辑隔离的流程中。在这种设计方案中,我们看到的是人们实际上将 Java 对象序列化到 XML 中,将它们通过网络发送,然后反序列化它们,用作为参数发送的对象来执行数据库查询,将数据库中的结果转换成 XML,然后将结果从网络上发送回去,仅仅只是为了将它转换成 Java 对象并最后进行操作。这种方法存在着几个严重的问题:

  1. 持久性对象应该总是保留在操作它们的业务对象的本地。这种对象序列化和反序列化的开销是您应该尽可能避免的。
  2. 还没有一种切实可行的、完全实现的 Web 服务事务处理规范。如果您使用带有 Mapper 对象的实体 Bean 或会话 Bean(如果您这样选择的话),在采用 RMI-IIOP 的 EJB 中,您就可以选择(尽管不是必须的)在外部事务范围内是否包括持久化操作。如果您在持久性对象和操作它们的业务对象之间引入了一层Web服务,那么您就丧失了这种能力。

一般来说,XML Web 服务对于细小颗粒的交互是不合适的,甚至还赶不上 RMI-IIOP。例如,不要将它放在应用程序的视图层和控制层之间。解析和 XML 生成的开销以及垃圾生成的开销将会使您的应用程序的整体性能大幅度下降。

原则:在应用程序服务器之间使用Web服务时要非常小心。

在很多方面,系统之间的互操作性是 Web 服务的特点。因此,如果您正连接到用 Microsoft 的 .NET 编写的系统,那么使用 Web 服务几乎是肯定的。尽管您也可以用其他的机制,比如 WebSphere Application Server 的 COM 支持,但是在 Microsoft 和 IBM 平台之间实现互操作性最好的解决方案可能就是 Web 服务。

有时,连接不同厂商完全不同的 Java 应用程序服务是可行的,但这种情况并不常见。(举例来说)通过使用 WebSphere 应用程序瘦客户端连接到 JBoss 或 WebLogic 服务器中用 WebSphere 编写的 EJB 是可能的。这会是一种比使用 HTTP 和基于 SOAP 的 Web 服务性能更好的解决方案。在另一方面,更常发生的情况是,您需要异步调用在另一个应用程序服务器或在某种遗留的服务器中编写的业务逻辑。在这种情况下,通过 JMS 发送 XML 看上起更合理,并且如果您将面向文档的 XML 包装在 SOAP 信封中,那么它甚至会更好;您可以利用 SOAP 的 Header 结构,甚至还可能获得一些现成的功能,比如 WS 安全性(WS-Security)支持。

解决 Web 服务的限制性问题

Web服务在处理分布式对象的一些有趣的问题方面已经证明是一种有用的方法。自从它引入起,HTTP 之上的SOAP 已经几乎变成了通过 Internet 进行应用程序到应用程序的通信的事实标准。随着一些大型网站(比如 UPS、Amazon 和 Google)开始支持 Web 服务标准,这项技术已经在 IT 业界确定了自己牢固的地位。

然而,当我们看一看在企业内部网环境中使用 Web 服务情况时,这个问题就不像讨论在全球性的 Internet 上可用的系统时那样有明确的答案。当在全球性的 Internet 上使用时,Web 服务具有很多的优点。例如:

  • 由于 Web 服务最常用的传输协议是 HTTP(大多数 Internet 基础结构也是以 HTTP 协议为基础构建的),所以通过 HTTP 对应用程序进行操作、管理、负载均衡和授权访问比通过其他协议要少一些麻烦。例如,大多数公司已经采用了一种 DMZ 防火墙策略,这种策略允许一组受保护的服务器接收 HTTP 或 HTTPs 协议上的传入流量,但不接收其他协议上的传入流量。这是一种颇具讽刺性的情况,大多数企业之所以允许使用 HTTP,是因为它被认为是一种“安全的”访问web 内容的协议。现在使用 Web 服务,所有类型的业务流量都可以通过企业的防火墙进行传输。仅仅假定因为您的 Web 服务流量是在 HTTP 上传输的所以就认为它是“安全的”是不合适的。您需要与安全性组织展开对话,讨论什么样的业务功能应该在 Internet 上公开以及应该采取怎样的防范措施来保护它们。
  • Web 服务很快地变得无处不在。这是由于非同寻常的历史性事件,Microsoft 和 Java 第一次同时支持一项分布式技术。由于现在能够理解基本协议的 SOAP 引擎和工具很常见,所以不再要求用与编写 Web 服务的服务器相同的工具来编写 Web 服务的客户端。这将使企业之间通过全球性的 Internet 进行通信成为可能,因为业务合作伙伴不需要假定会话的两边的实现方式。

然而,如果我们考虑一个系统,在这个系统中大多数用户将使用企业的内部网,那么克服 Web 服务和 SOAP 的下列障碍将变得更具有决定性的意义。这些障碍是:

  • 首要地,我们已经发现,现有的 SOAP 引擎在 Web 服务调用和使用 EJB 协议(RMI-IIOP)的等价调用之间的性能差异简直就有一个数量级。虽然使用 Web 服务的粒度非常大的方法对于业务合作伙伴之间很少进行的通信可能是适用的,但是将它们用于紧耦合、高容量的内部应用程序很可能就是不适当的。例如,每分钟都接收到来自各个用户的数十或数百个请求的呼叫中心(call-center)对于 Web 服务来说或许就不是一个好的候选者。在这样的一种情况下,生成和解析 XML 的开销是成问题的。
  • 尽管业界正在推进 Web 服务的标准化验证和授权,但不幸的是,大多数现有的 J2EE 产品组为此提供的支持并不完全,还没有达到它们为 J2EE 协议(比如 RMI-IIOP)所提供的支持的程度。

向前看,这些问题中的许多能够以一种巧妙的方式通过提议的 Web 服务的多协议支持来解决。例如,如果 WSDL 的标准 RMI-IIOP 绑定可以通过 JAX-RPC 实现,那么您就可以简单地选择正确的端口来完成您的 WSDL 中的工作。然而,由于这种方法的标准没有确定,所以这些问题还是现实的难题。

因此,没有一种分布方法可以解决所有的问题,很多组织已经得出了这样的结论,他们需要在其企业内支持多分布式对象协议和访问机制。可能需要把单个的应用程序 API 作为外部 Web 服务,对于内部远程客户端使用 HTTP 之上的 SOAP 和 RMI-IIOP 之上的 SOAP,在应用程序服务器中使用本地 EJB 引用,甚至有可能将 MQ 之上的 SOAP 用于异步交互。这个问题可以分成两个部分来解决。首先,我们如何通过多分布协议提供对业务逻辑的访问,其次,我们使用什么样的客户端编程模型来提供对远程业务逻辑的访问。

第二个问题实际上更值得关注,不过,我们也需要讨论一些解决第一个问题的方法。简单地说,通过应用由 [Alur] 提出的业务代表(Business Delegate)模型可以找到一种解决方案来提供通用、统一的客户端编程模型,这种模型与使用几种不同的远程技术中的哪一种无关。

多业务代表模式

业务代表是一种模式,它使得客户端可以不用关心远程业务服务的实现细节。这种模式的参与者如图34.2所示(改自 [Alur])。

图34.2 业务代表参与者
业务代表参与者
业务代表参与者

这里的关键之处是您的客户端需要使用一种远程业务服务。业务代表隐藏了如何获得业务服务的实现细节,并通过提供外部 API 来调用它的方法,这几乎是与业务服务相同的,但去掉了一些细节(比如远程异常处理)。为此,可以把对象查找的细节委托给查找服务(通常实现为一种来自 [Alur] 的服务定位器),并且在业务代表本身的方法中处理远程异常(和其他问题,比如重试)。

现在,在前一张图中,您应该留意到代表和业务服务之间的“使用”关系代表一组远程调用。这就是该模式的关键。就像 [Alur] 在第249页所讲的“主要的优点是隐藏了基础服务服务的细节。”采用这种模式的一个明显的结果是([Alur] 在第255页的讨论)将隐藏商业服务的远程性。事实上,该模式的作用远不止隐藏远程性。通过提供一种完全本地化的访问远程对象的机制,它隐藏了所用的基础远程协议,这样(只需对模式进行少量的修改),您就可以允许客户端从几种不同的远程协议中进行选择。

问题是,当大多数 J2EE 开发人员考虑业务代表模式时,他们仅仅想到它的远程 EJB 访问方面。[Alur] 中的代码示例只是展示了该模式在在这方面的应用,此外,关于该模式本身的大部分文本也只是提到将其与 EJB 一起使用。然而,这种模式并不仅限于 EJB。请考虑通过 JAX-RPC API 使用 Web 服务。使用 EJB 的这种模式产生的问题(例如,需要知道如何获得远程对象引用和需要值到如何处理远程异常和重试逻辑)同样也适用于 Web 服务。而且,该模式还提供了一种有用的方法来抽象出 EJB 2.0 中本地接口和远程接口之间的差别,而不必让您的应用程序设计人员显式地挑选使用哪一种主接口(远程还是本地)和本地或远程接口中的哪一个,您可以通过将决定隐藏在两个一组的业务代表的背后来抽象出细节。

我们得到的是一种稍微修改了的模型,我们显式地承认有几种不同的商业代理的实现可能被用在单个的商业服务中,每一个都是处理一个特定的情况需要的特定的访问机制。我们可以通过引入另外一组成员到模型中来将它明确表示出来。首先,我们必须决定需要有一个特定的接口以定义商业代表本身的方法。每一种不同的商业代表的实现方法(Web服务,远程EJB访问,本地EJB访问等等),必须实现代表接口。第二,我们需要提供一种机制,允许客户创建需要的特定的商业代表。对这个问题的最常用的方法是创建一个工厂,可以(根据一组输入的参数,或类中预设的一组配置参数)创建商业代表接口的许多不同的实现之一。应用这二个修改的结果可以从下面的图34.3看到我们得到的是一种略作修改的模式,在这种模式中,我们显式地承认有几种不同的业务代表实现可能应用到单个的业务服务中,每个实现都依赖于具体环境所需的特定访问机制。我们可以通过将另外两个元素引入到模式中来将它明确地表示出来。首先,我们必须决定需要有一个特定的接口来定义业务代表本身的方法。各种不同的业务代表实现(用于 Web 服务、远程 EJB 访问、本地 EJB 访问等等)都必须实现代表接口。其次,我们需要提供一种机制,使客户端能够创建所需的特定业务代表实现。这个问题的最常用的解决方案是创建一个工厂,它可以(根据一组输入参数或类中预设的一组配置参数)创建该业务代表接口许多不同的实现中的一个。应用这两项修改的结果如图34.3所示。

图34.3 具有工厂和接口的业务代表
具有工厂和接口的业务代表
具有工厂和接口的业务代表

现在,机敏的观察者可能注意到,这实际去掉了业务代表模式的一项优点--原始的模型使客户端不必使用工厂(在本例中为 EJBHome)来创建对象(EJB 引用),而我们又重新引入了一个工厂进来。然而,编程模型的稍微复杂一些相对于它提供的好处来说是很值得的。我们已经做的是用单个工厂替代了多重工厂(比如 EJBHome 和 JAX-RPC 服务),这返回一个适用于特定分布协的本地业务代表。

这种设计允许您做的是,可以利用每个可用的协议的优势而不必让您的客户端依赖于正在使用的特定协议。因此,让我们考虑这样一种情况,您有一个可以在企业防火墙内外运行的应用程序客户端。通过给工厂设定一个配置参数,相同的代码可以用在这两种情形之中;在防火墙之内您可以选择 RMI/IIOP,而在防火墙外面您可以选择 HTTP 之上的 SOAP。更重要的是,如果与远程对象通信的代码是一个大型业务组件的一部分,那么通过配置参数指示工厂改为使用一个本地 EJB 引用,该组件也可以加入 Servlet 或 JSP。因此,我们的最后的配置可能看上去像图34.4:

图34.4 多代表和服务器
多代表和服务器
多代表和服务器

事实上,这种模式可以扩展到任意数目的附加协议,只要那些协议支持相同的基本 RPC 语义。当然,对于每种协议,服务的质量可能有所不同。例如,事务(至少是今天)将不会通过 SOAP/HTTP 调用进行传递,但是它们将会通过 RMI-IIOP 调用进行传递。在安全性方面也有一些微妙之处需要考虑。然而,对于许多情况,这些差异是无关紧要的,该模式具有很高的安全性。

关于这种模式最后需要说明的是,只是在用于编写客户端的是实现业务代表的特定语言的情况下,它对您才是有价值的。因此,如果您用 Java 语言实现了业务代表的框架,这允许您透明地通过 RMI-IIOP 或 SOAP/HTTP 进行连接,而您的 Web 服务客户端可能是用 C# 语言编写的,那么这种模式就对您毫无用处。

WSDL 和 WSIF

您可能会认为像这样一种浅显易懂的模式(在记忆中)肯定将试图在一个或多个开放源代码的项目或商用产品中发挥作用。事实上,这种情况已经发生了,尽管它看起来好像从大多数开发人员的雷达屏上消失了。在2002年,IBM 向 Apache 社团捐赠了名为 Web 服务调用框架(Web Services Invocation Framework,WSIF)的技术。对 WSIF 的描述是这样的(在 apache.org 网站的 WSIF 主页上):“一种简单的 Java API,用于调用 Web 服务,而不管该服务是以什么方式在什么地点提供的。”这里的关键的不同之处在于,WSIF 设计成以 WSDL 作为使用协议的软件的“规范化描述”。如果您有了带有一组技术(比如 HTTP 之上的 SOAP 或 EJB)的各种绑定的 WSDL 文档,就可以通过 WSIF 提供者连接到用不同的分布技术实现的远程对象。

WSIF 主要是通过一个 API 进行使用的,其构造与 WSDL 非常匹配。然而,开发代理类的工具可以以这样一种方式来使用 WSIF API:该代理的外部 API 匹配 WSDL 描述的使用 JAX-RPC 映射的 Web 服务的等价 Java 定义。一些 IBM 的工具(比如 WebSphere Studio Application Developer- Integration Edition)在某些情况下能够生成这样的代理类来提供到 WSIF API 的简单 Java 接口。因此,在用WebSphere研究室应用程序开发者--集成版构建的JCA接口这种情况下,代理服务器类(作用上是一个商业代表)在WSIP的API上面生成,这将会随后被调入JCA WSIF的提供者。因此,WSIF提供了一种方法来处理在图中的左边需要的东西,但只有在整个系统是用WSDL来描述的,并且拥有(或能够编写)所有合适的提供者。因此,如果 JCA 接口是用 WebSphere Studio Application Developer - Integration Edition 构建的,那么代理类(其作用相当于业务代表)就可以在 WSIF API 之上生成,随后它将被调入 JCA WSIF 提供者。这样,WSIF 就提供了一种方法来处理图的左边所需要的东西,不过,只是当整个系统是用 WSDL 描述的并且您有(或者能够编写)所有适当的提供者才会如此。

对于有兴趣使用 WSIF 的人要说的最后的一句话是:虽然 WSIF 是一种令人感兴趣的技术,并对许多人来说是一种有用的方法,但是您应该记住,它现在是一种开放源代码的技术,而不是标准化的 JAX-RPC 规范中的一部分。在将来,我们希望 JAX-RPC 发展到具有和 WSIF 一样的多协议能力。现在,WSIF API 将会证明它有着比提供帮助更多的责任。因此,虽然 WSIF 现在还只能用作点方案(point solution),但是您应该认识到这种方法的前途。尽管 IBM 在内部将 WSIF 大量用于它自己的产品,但是或许不应该把 WSIF 看作是一个已经接受的标准 Web 服务 API--?对于您自己的实现,您应该坚持使用 JAX-RPC 和其他完全标准化的 API。

在SOA中选择正确的粒度级别

在第32章中, 您将要学会一种 IBM 已经命名为面向服务的体系结构(Services Oriented Architecture,SOA)的方法的基本要素。在开发面向服务的体系结构的过程中可能最困难的部分在于,决定 Web 服务的粒度的正确级别应该是什么。大体上这包括决定好的 Web 服务由什么和不由什么组成。在本章的前面,我们已经看到 Web 服务技术的一些适当的用法,比如将 Web 服务技术作为完全不同的系统类型(例如用 .Net 编写的服务器和为 WebSphere 编写的服务器)之间的通信机制,以及作为 Internet 上方便客户端-服务器之间通信的的一种方法。但是,Web 服务方法的应用比上面的两个范例要广泛得多。在下一部分中,我们将会讲解 Web 服务的一些适当的用法,这可能会帮助您更好地理解在您的设计中的何处应用这项技术。

统一的逻辑视图

回到第30章,我们讨论了一些关于使用会话 EJB 最佳实践和应用会话虚包(Session Facade)模式的技巧。我们讨论的事情之一是,会话虚包(Session Facade)的一个好的粒度级别是在服务层--这就是说您标识提供给一组通用客户端的逻辑服务,并在该层创建一个会话虚包(Session Facade)。

当您在做这件事时,在效果上,是在子系统中创建了一个统一逻辑视图。这个“大颗粒”的会话虚包(Session Facade)在您考虑如果使用 Web 服务时特别适合。第一,由于效率的原因,您无论如何不需要有一个连接到 Web 服务的“细颗粒”,唠叨的接口。就像我们前面讨论的一样,在 XML 的解析和生成中产生的开销将会成为缺点,这在 EJB 设计中是可以注意到的,然后还会放大它。所以,您将要查找尽可能少的方法来表示您的子系统的功能范围,然后再做工作使方法变成“大颗粒”,这样每个方法都执行一个完整的逻辑功能。

作为一个例子,考虑如果您在构建一个系统来在 Internet 上运行一个电子商务站点。您现在就能够根据域中的部分想象将会需要的不同的子系统:将会很快想到订单处理、配送和配送跟踪、退货和库存管理。这正好就是适合于 Web 服务的组件级别--通过展示整个子系统的单个逻辑视图,将会防止客户端知道子系统如何实现的细节,并且还隔离了随着时间的推移子系统实现中发生的变化。

可替换的组件

另一个我们在许多 Web 服务的设计中常常见到的主题是,需要表示一个特定的组件的几个不同的实现方法。在这个组件中,您既要隔离请求者以防其更改实现,又要提供对于该组件的许多不同风格的访问,或者是马上进行或者是在一段时间过后。

例如,考虑下面的问题。让我们假定您正在建立一个网站,用来向顾客提供保险报价。为了实现这一目标,您与几个不同的保险公司达成了向您提供保险报价协议。不过,您有一个问题:每个保险公司都有不同的机制来接受报价请求和向您提供报价。您将怎样设计您的网站来处理这个问题?

简单地说,这是 [Gamma] 提出的适配器模式能够向您提供帮助的地方。考虑下面的设计(图34.5):

图34.5 保险代理设计
保险代理设计
保险代理设计

您能够编写的是一个代理(Broker)组件,这个组件将做两件事:查找本地 UDDI 存储库以找到实现了特定 WSDL 接口的各种适配器的引用,然后使用这个通用的 WSDL 接口来获取所有保险公司(Insurer)的报价(通过发送相同的 getQuote 请求到所有的适配器)。每个特定于保险公司的适配器(这是您将要负责进行编写)将会把 Web 服务请求翻译成保险公司(Insurer)自己的报价系统能够理解的请求。有几种方法可以做到这一点:

  1. 最简单的方法(无为法)是仅仅让保险公司他们自己实现描述 getQuote 接口的 WSDL 文档!在这种情况下,您根本不需要适配器,而只要简单地将请求传送过去就可以了。然而,在这种情况下,即使有一个简单的适配器也可能是很有帮助的--您可能需要记录出站的请求,或从一种协议(譬如 HTTP)翻译成另一种协议(比如 HTTPs)。这种类型的中介作用是 WebSphere Application Server、Network Deployment 的组件的功能,称为 Web 服务网关(Web Services Gateway)。它允许您设置过滤器,用来执行日志记录、协议翻译或许多其他有用的功能。您甚至还可以为网关中的开发编写您自己的过滤器。
  2. 如果您的业务合作伙伴不能实现您的 WSDL,但给您提供一种类似的文档类型,那么您就可能能够编写一个适配器,用来将他们现有的格式转换成您自己的格式。例如,他们可能向您提供了一种现有的系统,您可以通过 HTTP 来访问以 XML 文档(采用他们自己的惟一专用格式)的形式给出的报价。在这种情况下,您可以编写一个 Web 服务来使用 XSLT 文档,以便将他们的 XML 格式转换成您的 WSDL 文档指定的格式。
  3. 最后,如果您通过标准的 J2EE 协议(比如 WebSphere MQ 之上的 JMS或带有 IBM CICS 的 JCA)来访问现有的业务逻辑,那么您就可以将 Web 服务编写成 EJB 或 Java Bean 来使用该协议和适当的 JCA、JDBC 或 JMS 连接器,以便将请求发送到目标系统上,然后取回报价,然后将响应转换成您需要的格式。这里,您可以使用 WSDL2Java 工具来生成一个简单的 Skeleton,这样您就可以填写恰当的转换逻辑。

这种方法的优点是,您的代理(Broker)系统现在完全独立于每个的保险公司--添加另一家保险公司非常简单,只需实现一个新的适配器然后将该适配器注册到 UDDI 存储库就可以了。同样地,更改适配器的实现(例如,如果在您已经使用一个为 CICS 编写的适配器之后,某家保险公司决定实现他们自己的兼容Web服务)根本就不会影响代理。Web 客户端软件将会只需向代理(Broker)请求一组特定情形下的报价,然后将结果展示给用户。

可组合的组件

最后,您需要问您自己您是否需要将您的系统分解,然后用一种可配置的方法组合到一个大的系统中?换句话来说,您是否需要实现一个或更多使用您的系统的不同部分的工作流程?工作流程是一种描述一组步骤(通常称为活动)的方法,这组步骤组合起来执行一个特定的业务过程。例如,在保险业,有好几个步骤组成赔偿支付。如果您想象每个步骤是由一个单独的 Web 服务来实现的,那么赔偿支付的过程将会包括用一种特定的次序调用不同的服务,根据前一个服务的调用结果,有些服务可能会被跳过或绕过。

在2002年,由 IBM、BEA 和 Microsoft 发布了一个名为 Web 服务的业务流程执行语言(Business Process Execution Language for Web Services,BPEL4WS)的规范,该规范描述了如果将 Web 服务组合成工作流程中,以便形成更大的、组合式的 Web 服务。您应该注意到这并不一定意味着Web服务使用 HTTP 之上的 SOAP -- 这包括所有 WSDL 定义的服务,它可能包括使用 RMI?IIOP 的 EJB。BPEL4WS 的特色是提供了下列功能:

  • 一种指定任务之间的任务(Web 服务)和事务的机制。
  • 支持“微流程”(在自动事务中产生的流程,比如在单个的 EJB 调用中)或“宏流程”(跨几个事务的流程,并且可能经过很长的时间)的能力。
  • 一种简单的机制,用来指定条件执行和任务选择。
  • 一种成熟的错误处理机制,包括在出现工作流程“回滚”到特定的点这种情况时要处理的补偿事务。

工作流程系统包括两个部分:一个工作流程指定工具,一个工作流程执行引擎。在这两者之间使用一种诸如 BPEL4WS 之类的标准规范语言,这样做的的好处是它允许这两者随着时间的推移变成可插入的。IBM 有一个很成熟的工作流程指定和优化工具,叫做WebSphere Business Integration Modeler(以前称为 HoloSofx)。到2003年中,这个工具将会完全支持 BPEL4WS。现在,IBM 的 WebSphere Application Server Enterprise Edition 支持 BPEL4WS 的前身 Web 服务流程语言(Web Services Flow Language,WSFL),它也将会在2003年末升级为支持 BPEL4WS 功能。也还有作为 IBM WebSphere Studio Application Developer Integration Edition一部分的工作流程指定工具,它也将会升级为能够与遵守 BPEL4WS 规范的 WebSphere Business Process Choreographer 版本一起使用。

从互操作性学到的教训

用不同的的语言或不同的工具集编写的 Web 服务提供者和 Web 服务请求者之间的互操作性,已经变成 Web 服务提供的好处的主要范例。事实上,这可能是它们变得如此流行的惟一理由。让我们面对下面的事实:IT 业已经分成两大敌对的阵营, Microsoft 阵营和 Java 阵营,而任何可以让这两个阵营达成停火协议的事情都是好事。在真实世界的情形中,拥有一些方法以让用一种技术编写的代码来调用用另一种技术编写的代码是极为有用的。这可以使同一个公司中来自不同组织的系统能够第一次实现通信(由于快速的公司合并,这不是少见的),此外,还可以使公司能够与使用一些不同技术的业务合作伙伴进行业务来往。然而,尽管互操作性的承诺是我们看好 Web 服务的主要理由,但现实的情况是互操作性并不很轻松地就具有的。您从一开始就得学习它并将其设计到您的系统中,就像您在可伸缩性、性能、可靠性和安全性方面进行的设计一样。

对于开发人员幸运的是,通过一个叫做 Web 服务互操作性组织(Web Services Interoperability Organization,WS-I)组织开展的工作,对规范的解释的混乱局面开始有所改观,并开始形成一些规则。这个组织是一个行业协会,其章程是促进 Web 服务厂商之间的互操作性。WS-I 将会提供工具厂商和开发人员用来确保 Web 服务的互操作性的推荐标准和工具。由 WS-I 制订的第一个也是最重要的一个规范是 WS-I 基本概要(WS-I Basic Profile),这个规范描述了一部分方法,在这些方法中,可以用四种主要的 Web 服务规范(WSDL、SOAP、HTTP 和 UDDI)来确保互操作性。虽然 WS-I 基本概要(WS-I Basic Profile)中的大部分推荐标准解决的只是对 Web 服务的工具集的厂商感兴趣的问题,但同时也有一些您必须采取的步骤,以确保您的 Web 服务是遵守 WS-I 基本概要(WS-I Basic Profile)的,并且确保可以与他们的 Web 服务进行互操作。特别是,在 WSDL(和 SOAP)规范中有两个问题是属于这种类型的。它们是编码样式和绑定样式。

编码样式和互操作性

SOAP 规范指定了一个名为“encodingStyle”的模式,它可以取两个值,“encoded”和“literal”。这指的是表示参数的 XML 在通信线路上是如何定义的。编码的(encoded)指的是 SOAP 规范的第5节,这一节定义了将编程语言的类型映射到 XML 的基本机制。而文字的(literal)意味着您不用做这些工作。取而代之的是,这些类型信息是由外部机制提供的,更像使用 XML schema来确切地定义 SOAP 消息中使用的类型的 WSDL 文档。

这之中的缘故是因为 SOAP 规范是在采用 XML Schema 规范之前编写的。因此,原始的 SOAP 规范必须与方法调用时发送的参数一起提供一种方法来指明编码类型信息,因为没有已接受的方法来指定它。与 XML Schema 完全不同的地方是数组。SOAP 规范的5.4.2节指定了一种特别的机制来表示 XML 中的编程语言数组,它使用一种特别的 SOAPEnc:ArraySchema 类型。同时,编码信息(比如 <item xsi:type="xsd:string">)通常与用 SOAP 编码标准的 SOAP 消息体元素相关联。

然而,自从采用 XML Schema 之后(您会记得,WSDL用来表示它的类型),大多数语言通过指定它们自己的从 XML Schema 到编程语言类型之间的映射(或序列化规则)已经使需要 SOAP 编码变得过时。例如,JAX-RPC 规范惟一地指定了如何将 Java 类型映射到 XML Schema 元素,反之亦然。这消除了在 XML 中需要额外的编码信息的需要。因此,作为结果,SOAP 编码不再流行,并已经被文字编码所取代,在文字映射中由 XML Schema 文档(通常是 WSDL 文档的形式)从外部指定映射。在外部用一个XML架构文档指定,通常是 WSDL 文档的形式。

因此,如果您可能需要互操作性,就不应该计划让您的 Web 服务使用 SOAP 编码。您都应该计划改而使用文字编码,只要有可能的话。在使用 Web 服务时开发人员遇到的大多数互操作性问题主要来源于对 SOAP 编码的不同解释,所以完全避免使用它是一种有用的策略。事实上,WS-I 已经到达了这一步,它们明确地将使用 SOAP 编码排除在它们的基本互操作性概要之外。

绑定样式和互操作性

现在是讨论其他问题的时候了,这个问题就是绑定样式。WSDL 规范在它的 SOAP 绑定中指定了两种不同的“绑定样式”。绑定样式属性的值是“RPC”和“Document”。其含义是,如果一个WSDL文档指定了一种具有绑定样式属性设置为“RPC”的操作,那么接收者就必须要用 SOAP 规范第7节中的规则来解释消息。这意味着,例如,在 SOAP 体中的 XML 元素(称为“包装的元素”)必须具有一个与将要调用的对应编程语言操作名称相同的名称。在这个元素中的每个消息部分必须严格地对应(在名称和次序方面)于该编程语言操作的参数。最后,必须只有单个的元素返回(这个元素必须命名为 XXXResponse,其中,XXX 是语言中对应的操作的名称),返回元素中严格地只包含一个元素,那是操作的返回值。

“Document”绑定样式较为宽松。文档绑定样式中的消息必须仅仅由形式良好、名称空间限定的 XML 组成。由接收它的 SOAP 引擎来决定如何解释它。现在,我们已经说过,使用“Document”绑定样式和“Literal”编码来表示 RPC 是很常见的(例如在 Microsoft 的工具中)。在这样的情况下,发送者将还要遵循 SOAP 规范的第7节中的许多或所有的规则来描述消息,但是要由接收者来决定如何处理这些消息,要么作为一个 RPC 调用,要么作为需要处理的文档。特别地,还有一个外部元素来表示(和命名)操作,而这个元素包括表示消息参数的元素。

也许在 Web 服务设计社区出现的最不同寻常的二分法是,从消息传递背景采用 Web 服务的设计和从面向对象编程背景采用 Web 服务的设计引起的冲突。[Sun] 在区分面向文档的 Web 服务和 RPC 样式的 Web 服务时产生的错误典型地体现这种二分法。他们声明面向文档的 Web 服务仅适用于异步消息处理而 RPC 样式的 Web 服务应用于同步服务。他们错过了一个有价值的地方:使用场景的选择如何应用到绑定样式的问题。要理解这一点,让我们研究一下WS-I 使用场景定义中的三种使用场景。它们是:

  • 单向--单向消息是一种不需要来自 Web 服务提供者的响应的消息。Web 服务消费者发送一个请求到提供者,但是不等待响应。这是在 [WSDL] 中定义的并在 [WS-I] 中加以明确化。
  • 同步请求/响应--这是最常见的场景,它包括 Web 服务消费者发送一个请求到提供者,然后在提供者处理请求并随后提供一个响应时保持同步等待。这是所有的远程过程调用(RPC)机制实现的操作语义,因为它是在过程性编程语言和面向对象的编程语言中的标准函数调用语义。
  • 基本回调--基本回调场景由两个同步请求?响应场景组成,以便能够进行异步处理。初始的请求是发送到提供者的,包括用于指定接收者的信息。请求立即产生来自提供者的接收确认(而不返回一个值到接收者)。然后在以后的某个时刻,接收者将会发送一个请求到初始的接收者(“回调”)并给它提供初始请求者所请求的全部信息;对这个请求的响应将会是另一个确认。这两个交互是通过相关标识符(Correlation Identifier)连接在一起([Hohpe])。

从这里得出的要点是,RPC 样式的 Web 服务一般只是文档样式的服务的一部分。而文档样式的服务可以用于在 WS-I 中定义的三个使用情景的任何一个,RPC 样式的Web服务只限于同步请求/响应场景。更重要的一点是,如果您选择全面使用文档样式的消息,不管您选取了哪一种使用情景,它们将都是有效的。采用这种方法有一些明显的优点,也就是不管您选取了哪一种使用情景,都可以采用一组设计原理来指导设计。这将导致系统更一致且更容易维护。

选择使用文档样式与 RPC 绑定样式的时机

尽管存在赞成或反对全面使用文档样式的体系结构上的争论,但事实是 WS-I 已经声明 RPC-文字样式和文档-文字样式的 Web 服务对于互操作性都是允许的。特别是,您必须根据您正在实现的特定场景的详细情况,评估在您的 Web 服务中要采用样式还是 RPC 样式。当您想要在您的处理模型中保持一致时,您可以通过一致的方法使用文档或 RPC 样式来达到这个目的。您不必在您的整个业务中只选取一种样式。

下面的一些指导原则可以帮助您确定在一个特定的场景中使用哪种模式:

  • 有些 XML 预定看作是文档(例如,考虑 newsfeed 的情况)。当消息的有效载荷将作为 XML 进行处理时(例如,当它将要被转换成另一种格式并直接存储在数据库中,或者,如果该有效负载将要被合并到其他的 XML,然后发送到另一个目的地),就应该采用文档样式。
  • 如果您的应用程序已经有了 XML 接口,您将可能需要使用文档样式。类似地,如果您正在发送符合工业 XML 词汇的数据,您将可能需要使用文档样式。
  • 当执行函数或发送将会被分析的数据时,您需要小心地评估在文档和 RPC 之间的选择。RPC 样式比较简单并且有时还提供更好的工具支持。文档样式提供了更大的灵活性和非关联性,并且在某些情况下(有许多元素的大消息)能够大幅度地压缩消息的大小,但可能需要更多的 XML 专门技术和手工编码。

然而,尽管存在两种模型都已被接受的事实,但这方面的实践情况是,使用文档-文字样式的通信比使用 RPC 样式的通信发现的问题要少。因此,如果您预先考虑您的服务的互操作性,我们将会强烈建议您计划在您的 Web 服务中使用文档-文字样式。当这样做时,要清楚地认识到其限制,了解哪些XML架构元素能够被 JAX-RPC 和其他厂商的工具集理解。

关于互操作性的最后说明

在不同系统之间的互操作性是使用Web服务的主要原因之一。然而,您不能仅仅假定您的Web服务将会是可互操作的,尽管您遵循了我们上面讨论的步骤;您需要测试您的服务来确保互操作性。我们的建议是,计划同时通过与预计将使用您的服务的一样多的各种客户端来测试您的服务。例如,我们将会建议几乎所有的服务都在 Java 和 .NET 两种客户端中进行测试。这对于避免事后出现不良的后果是很重要的。您也应该随时跟踪已经发现的最新的互操作性问题。可以把 WS-I.org 和 soapbuilders.org 网站作为发现这些问题的来源。

总结

尽管 Web 服务并不是所有问题的解决方案,但是它们确实能够帮助解决一些问题,特别是使跨语言或跨系统的集成问题变得容易。在本章中,您已经了解到一些关于面向服务的体系结构如何能够帮助您获得这些好处,也了解到如何设计您的系统,以便更容易地实现互操作性,同时使得将最好的通信机制的优势应用到每种服务成为可能。特别地,您已经掌握了下列要点:

  • Web 服务并不是对所有的条件都是适用的。它们在解决各种类型的互操作性问题时很有效(与 Microsoft 的工具的互操作性,与现有的启用 Web 服务的系统的连接,或在处理防火墙问题时),但在很多会话的二边都能够委托的设计中不是那么有效。
  • 使用业务代表模式可以支持各种场景,在这些场景中,客户端能够根据需要的服务质量的不同来选择不同的传输。
  • 当计划使用Web服务时,您应该认识到 Microsoft 和 Java 的工具在处理样式方面的不同之处。我们建议只要互操作性是可能的,就使用文档-文字样式的 Web 服务。

相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=WebSphere
ArticleID=55441
ArticleTitle=Web 服务的体系结构和最佳实践
publish-date=12012003