第6章 服务模式 在 .NET 中实现 Service Gateway(服务网关)

时间:2024-12-17 00:04:50

上下文

您正在设计企业应用程序,该程序需要使用由其他应用程序提供的服务。该服务定义了一个合约,所有服务使用者要访问该服务都必须遵守该合约。该合约定义了与此服务通信所需的技术、通信协议和消息定义等内容。要与该服务通信,应用程序需要按合约中的详细说明履行其责任。

问题

如何将该服务所规定的履行合约责任的细节与应用程序的其余部分分隔开来?

影响因素

在设计使用由其他应用程序提供的服务的应用程序时,必须考虑下列影响因素:

  • 履行使用者的合约责任需要实现安全和通信机制,例如验证、封送、加密和消息路由。这些机制通常以不同于应用程序业务逻辑的速率和原因发生更改。
  • 该 合约指定的数据格式可能与应用程序的内部表示形式不同。如果是这样,则必须转换数据。有时这种转换非常简单,就如重命名字段或转换数据类型,但有时这种转 换涉及复杂的结构和语义转换。例如,大多数服务都会公开粗粒度的、基于类型的接口,以优化它们在分布式环境中的使用。因此,从面向对象的应用程序调用对服 务的操作时,来自多个应用程序细粒度对象的信息通常需要进行聚合,并转换为合约所指定的格式。同样,来自该操作的响应通常需要打散,然后再映射回细粒度对 象。
  • 您的组织可能无法控制由服务指定的合约。如果合约发生更改,将需要尽可能减少应用程序代码所受的影响。
  • 可以在应用程序与服务之间提供连接的通信通道通常会向该应用程序公开常规的、低级别的应用程序编程接口 (API)。此 API 可能包括 SendData 等常规函数。在大多数情况下,应用程序需要通过 ValidateCreditCard GetCustomerAddress 等方法来处理语义更加丰富的接口。
  • 某些合约可能会指定异步消息传递,即它们可能不会立即返回结果。而服务使用者必须准备接收来自该服务的单独结果消息。处理这些来自服务的传入消息所需要的事件驱动编程技术可能会极大提高应用程序的复杂程度。

解决方案

将实现合约使用者部分的代码封装到它自己的 Service Gateway 组件中。服务网关在访问服务时的作用类似于数据访问组件在访问应用程序数据库时的作用。二者都是作为其他服务的代理,封装连接源服务的细节,并执行所有必要转换。

Service Gateway 是特殊类型的 Martin Fowler 的 Gateway 模式 [Fowler03],此模式适合在面向服务的体系结构中使用,因此其主要任务是封装使用服务的应用程序对外部系统的访问。Service Gateway 通常与 Remote Facade [Fowler03] 交互,而不直接与外部系统进行交互。Remote Facade 可封装提供服务的应用程序中的复杂功能,并将该功能作为一个简单接口向使用服务的应用程序公开。Service Interface 是特殊类型的 Remote Facade,适合在面向服务的体系结构中使用。在面向服务的体系结构中,使用服务的应用程序的服务网关通常与提供服务的应用程序所公开的服务接口进行协作。下图说明了这种关系。

第6章 服务模式 在 .NET 中实现 Service Gateway(服务网关)

图 1:使用服务接口的服务的 Service Gateway

Service Gateway 组件封装了与服务进行通信的低级别细节。这些细节包括但不仅限于以下内容:

  • 通信通道。 Service Gateway 封装了与服务进行通信所需的所有低级别网络通信功能。例如,Service Gateway 隐藏了所有使用 SOAP over HTTP 与 Web Service 进行通信的细节。
  • 数据格式。 Service Gateway 可 以在应用程序中内部信息组织与服务的通信合约所规定的格式之间建立映射。例如,应用程序可能由一组相互协作的细粒度对象组成,但其所用 Web Service 可能需要将 XML 文档作为输入内容,并且提供 XML 文档作为结果。网关负责在细粒度对象接口和 XML 文档之间进行转换。
  • 服务发现。对于简单情形或不太复杂的情形,Service Gateway 应该封装发现适当服务的过程。这可能包括在配置文件中查找服务的网络地址,或使用 UDDI 等服务储存库。对于复杂的情形,例如需要根据不断变化的数据动态决定调用适当服务,服务发现功能可能会封装在它自己的服务网关组件中。
  • 进程适应器。 Service Gateway 应该适应应用程序的业务进程,以便与该服务一起工作。例如,对服务网关的单个调用可能会导致多次调用一个或多个服务操作。因此,服务网关向应用程序所提供的接口应该参照应用程序的进程,而不是参照通信和安全性协议。
  • 异步和同步调 用语义。 Service Gateway 将根据合约指定的调用语义调整使用服务的应用程序的调用语义(异步或同步)。例如,使用服务的应用程序的设计可能不支持合约中指定的异步调用语义。这时,使用服务的应用程序的服务网关必须将该应用程序的同步调用转换为合约中所指定的异步协议。

无需将 Service Gateway 实现为一个对象。实际上,将某些功能分隔到单独对象中可能更加有利。例如,如果使用单独对象,使用代码生成方法来创建网关的某些部分可能更为简单。如果服 务提供者发布了描述所需数据格式(例如,以 WSDL 或 XML 架构的形式)的元数据,用于实现内部应用程序格式与服务期望格式之间的映射数据的代码则是这种映射的理想选择。此元数据可用于生成封装这种映射的强类型 类。

测试考虑事项

Service Gateway 可以明显提高系统的可测试性。服务网关会将访问服务的所有细节封装到一个组件中,并将该组件隐藏在不直接依赖于基础通信通道的接口之后。因此可以在测试过程中将网关替换为 Service Stub [Fowler03]。Service Stub 根本不会访问外部系统,但会将用于模拟外部系统的结果直接返回给应用程序逻辑。Service Stub 还可用于模拟错误情况,例如不可用的外部服务。

结果上下文

使用服务网关组件将应用程序和与服务通信细节隔离开来,具有下列优缺点:

优点

  • 通过将服务访问逻辑与应用程序的其他部分分隔开来,可以轻松更改应用程序所访问的服务。例如,您可能希望更换为相同服务的较新版本,或使用其他供应商提供的服务级别保证更好的服务。如果可以自动生成进行数据映射的代码,则切换到其他服务更加容易。
  • Service Gateway 可隐藏从应用程序访问服务的复杂性。这样就提高了应用程序组件和服务访问组件的重用性。应用程序不直接引用服务,因此不受任何实现细节和服务位置的影响。 将服务访问逻辑封装到一个单独的层中还会提高访问逻辑的重用性,因为只要使用相同的传输和验证机制,就能为多个服务调用所使用。
  • Service Gateway 是提供公用功能(如异步调用、缓存和错误处理)的理想工具。

缺点

  • Service Gateway 增加了复杂性,这对于简单解决方案可能并无必要。特别是当您的组织将仅访问几个相对静态的服务,则可以不需要支持映射组件自动生成所需的工作和基础结构。
  • 一个特定服务网关负责与一个服务交互。如果要协调多个服务,则必须由另一个组件处理,例如 Three-Layered Services Application中指定的业务过程组件。

服 务网关通常包含在一个应用程序中。因此可能导致代码重复,前提是:如果多个应用程序访问同一服务,则两个应用程序可能重复网关功能。开发可重用服务网关组 件是一个备选方法。另一个解决方案是,将公用功能提取到在组织内本地部署的该公用功能自己的服务中。在这种情况下,还可使用前一章讨论的某些分布式计算解 决方案(例如 Remote Facade)。