在构建企业类解决方案时,不仅涉及到开发自定义软件,而且还涉及到将该软件部署到生产服务器环境中。这是软件开发工作与系统基础结构工作的交叉点。如果将这两个原则放在一起,则更加要求您对所涉及到的问题有一个基本的了解,并具备一套强大的应用程序和系统基础结构技能。单个小组极少具备所需的全部技能;因 此,部署活动通常需要几个具备专门技能的小组通过协作完成。为了简化讨论,本章假定有两个小组:应用程序开发小组和系统基础结构小组。
应用程序开发小组负责开发和维护一组能够满足应用程序要求的软件组件。该小组主要在乎的是能否快速而又灵活地满足功能要求。其成员设法通过创建使系统便于扩展和维护的软件抽象来管理复杂性。
系统基础结构小组负责构建和维护服务器及网络基础结构。它的成员主要关心诸如安全性、可用性、可靠性和性能等操作要求。稳定性和可预知性是成功的关键因素,它们主要通过控制更改和管理已知的良好配置来解决。
影响应用程序开发小组的因素与影响系统基础结构小组的因素有很大的区别,其结果是在这两个小组之间存在固有的牵制。如果这种牵制得不到解决,则最终的解决方 案对于其中的一个小组来说可能是最优的,但它将不是最优的业务解决方案。为了提供一个完整的、针对业务整体需求而优化的软件密集型企业解决方案,解决该牵制是一个关键因素。
本章中的模式通过指导如何以最优方式构造可高效满足解决方案要求的应用程序和技术基础结构,有助于减小小组之间的牵制。随后,通过这些模式讨论如何将软件结构映射到硬件结构。特别是,本章提供了一组使您能够实现下列功能的模式:
尽管层和级的概念通常可互换,但是本章中的模式对这两个术语进行了明显的区分。层是构成软件解决方案的元素的逻辑结构机制;级是系统基础结构的物理结构机制。该群集中的第一组模式按层处理软件应用程序的逻辑结构。第二组模式按级展开系统基础结构的物理结构。图 1 显示了这两组模式及其相互关系。
图1部署群集
该群集中的第一个模式是 Layered Application, 分层应用程序),它按一组逻辑分层来组织软件应用程序,以便管理依赖性并创建可插入的组件。该模式确切定义了何为层,然后描述了如何定义自己的层。它还描 述了基于分层应用程序构建并扩大了其价值的其他一些技术。Layered Application 的一个主要好处在于其完善定义的接口和强大的依存关系管理使您可以非常灵活地部署应用程序。虽然很难在多个服务器之间分布单层应用程序,但是在层边界处划 分应用程序并将不同的部件分布到多个服务器更容易。但是,由于形成分层决策的因素不同于形成分布决策的因素,所以并非所有的层边界都形成了很好的分布边界。
Layered Application 在软件开发世界被广泛应用。针对企业应用程序的常见模式实现是 Layered Application。这种实现定义了三个层:表示、业务和数据。虽然您可以添加更多层,但是对于企业业务应用程序,几乎总是需要这三层。
大多数企业应用程序现在都使用基于组件的方法进行开发。尽管组件有多种定义,但其中最简单的定义是:组件是一个可单独部署的独立软件功能。运行时,可在公开一组约定接口的执行环境中插入和拔出组件。这种可插拔性在部署期间提供了巨大的灵活性。组件的独立特性使它们成为了可针对其进行部署决策的最小单位。
Three-Layered Services Application (三层服务应用程序)优化Layered Application,以便为那些与面向服务的更大体系结构中的其他企业应用程序协作的企业应用程序提供具体的构造指导。它详述前面描述的三个典型层,并为每个层定义了一组组件类型。
该群集中的下一组模式强调物理基础结构。这些模式的上下文是支持跨多个服务器分布应用程序的基础结构。特别是,这些模式不涉及大型机或其他大型多处理器基础结构配置。
Tiered Distribution(分级分布)按一组物理级来组织系统基础结构,以便提供针对特定操作要求和系统资源使用而优化的特定服务器环境。单级基础结构不够灵活;一般来说,服务器必须按照最严格的操作要求进行配置和设计,并且必须支持用户最多时在高峰期对系统资源的使用。与之相反,多级支持多个环境。您可以针对一组特定的操作要求和系 统资源使用来优化每个环境。然后,可以将组件部署到最能满足它们的资源需求并使它们能够以最佳方式满足其操作要求的级上。使用的级数越多,部署每个组件时 供您选择的范围就越大。
Three-Tiered Distribution(三级分布)优化了Tiered Distribution ,以便为构造具有基本安全性和其他操作要求的 Web 应用程序提供特定的指导。该模式建议按三级组织解决方案服务器:客户端、Web 应用程序和数据。客户端级和数据级的功能不言自明;Web 应用程序级作为应用程序业务组件以及 Web 表示组件的宿主。对于具有更严格的安全性和操作要求的解决方案,您可能应该考虑将 Web 功能移到单独一级上。
该群集中的最后一个模式是 Deployment Plan(部署规划),它描述用来将组件分配到级的过程。在分配过程中,一定要确保应用程序开发小组和系统基础结构小组之间良好的沟通。前面讲述的所有模式都能够增加 软件应用程序和系统基础结构的部署灵活性。Deployment Plan 取决于部署灵活性,这样小组在解决利益冲突时选择范围更广。解决这些冲突之后,可以有更多的机会来提供具有最优业务价值的解决方案。作为对该模式的总结, 最后描述了通常在将该过程应用于企业应用程序时生成的四种常见模型:简单 Web 应用程序、复杂 Web 应用程序、扩展企业和富客户端。
Layered Application(分层应用程序)
设计复杂的企业应用程序,该应用程序由跨越多个抽象级别的大量组件组成。
如何构造应用程序,以支持诸如可维护性、可重用性、可伸缩性、可靠性和安全性等运行要求?
构造应用程序时,必须协调环境内的下列影响因素:
将解决方案的组件分隔到不同的层中。每一层中的组件应保持内聚性,并且应大致在同一抽象级别。每一层都应与它下面的各层保持松散耦合。 Pattern-Oriented Software Architecture, Vol 1对分层过程的描述如下:
从最低级别的抽象开始--称为第 1 层。这是系统的基础。通过将 第 J 层放置在第 J-1 层的上面逐步向上完成抽象阶梯,直到到达功能的最高级别 - 称为第 N 层。
图 1 显示了此分层架构的图示。
图 1: 层
结构
Layered Application的关键是依赖性管理。一层中的组件只能与同一级别中的对等实体或较低级别中的组件交互。这有助于减少不同级别中的组件之间的依赖性。有两种通用的分层方法:严格分层和松散分层。
严格分层方法限制一层中的组件只能与对等实体以及与它紧邻的下面一层进行交互。例如,如果应用程序的分层如图 1 所示,那么,第 J 层只能与第 J-1 层中的组件进行交互,第 J-1 层只能与第 J-2 层进行交互,依次类推。
松散的分层应用程序放宽了此限制,它允许组件与位于它下面的任意层中的组件进行交互。因此,在图 1 中,第 J 层不仅可以与第 J-1 层交互,而且可以与第 J-2 层和第 J-3 层交互。
松散方法可以改善效率,因为系统不必将简单调用从一层转发到下一层。另一方面,松散方法在层之间不提供相同的隔离级别,并使得在不影响较高层的情况下换出较低层变得更困难。
对于包含许多软件组件的大型解决方案,常见的方法是使不内聚的大量组件处于同一抽象级别。在这种情况下,每一层可以进一步分解为一个或多个内聚的子系统。图 2 显示了由多个子系统组成的表示层的可能的 UML 表示法。
图 2: 由子系统组成的多层的 UML 表示
通常使用下列技术扩充基本的 Layered Application 模式。
动力
分层应用程序中存在两种基本的交互模式:
在由上而下模式中,外部实体与栈中的最高层交互。最高层使用较低级别层的一个或多个服务。反过来,每个较低级别都使用它下面的层,直到到达最低层。
由于本文仅仅进行讨论,因此此模式假定外部实体是客户端应用程序,并且分层应用程序是将其功能作为一组服务公开的基于服务器的应用程序。图 3 是描述常见的由上而下方案的 UML 序列图。
图 3: 由上而下方案的序列图
在此方案中,客户端应用程序使用基于服务器的应用程序提供的一组服务。这些服务由服务器应用程序的最高层公开。因此,客户端必须只与最高层交互,而无法直接了解任何较低的层。有几个因素需注意。
首 先,一个传入调用会导致多个传出调用。第 N 层上的服务 1 的调用说明了这种情况。当较高级别服务聚合几个较低级别服务的结果,或协调多个必须按特定的顺序执行的较低级服务的执行时,通常会发生这种情况。例 如,ASP.NET 页可以将客户域组件的输出提供给订单组件,而订单组件的输出将提供给发票组件。
第二,此方案说明了松散的分层方法。服务 2 的实现绕过了所有中间层而直接调用第 1 层。这种情况的常见示例是绕过任何中间业务逻辑层而直接访问数据访问层的表示层。数据维护应用程序通常使用这种方法。
第三,顶层服务的调用并不一定会调用所有层。这一概念是通过服务 1 到操作 2 顺序来说明的。当较高级别可以处理自身中的调用,或者缓存了较早的某个请求的结果时,就会发生这种情况。例如,域组件通常缓存数据库查询的结果,这使得将来调用时不必调用数据访问层。
在由下而上模式中,第 1 层检测影响较高级别的情形。下面的方案假定第 1 层监视某些外部实体(例如,服务器应用程序所运行的服务器的文件系统)的状态。图 4 以 UML 序列图的形式描述了典型的由下而上方案。
图 4: 由下而上方案的序列图
在此方案中,第1层监视本地文件系统的状态。当它检测到更改时,将激发由第 J-1 层中的组件公开的事件。然后,该组件调用第 J 层(更新域层的状态时所处的位置)的回调委派。然后,域组件通知第 N 层它已被第 N 层为此目的而提供的委派更新。
与第一种方案相同,在一个级别中的输入会导致多个输出。较低层可以通知高于它的任何层,而不仅仅是它上面的那一层。最后,通知不一定必须穿过整个链。
请 注意由下而上方案中层的交互与由上而下方案中层的交互有哪些不同。在由上而下方案中,较高层直接调用较低层,因此依赖于这些层。但是,在由下而上方案中, 较低层通过事件、回调和委派来与较高层通信。要防止较低层依赖于较高层,这种级别的非直接性是必需的。使较低层依赖于较高层减少了分层体系结构所提供的许 多优点。
实现
实现Layered Application 模式有两种基本的方法:
创建您自己的分层架构
Buschmann提供了关于自己实现分层应用程序的深入讨论。这里提供的仅仅是简述。如果您需要定义自己的分层应用程序,那么强烈建议您研究 Buschmann 中的 Layers 模式。此过程概述如下:
重用现有的分层架构
另 一种方法是重用现有的参考分层应用程序,以便为您的应用程序提供所需的结构。规范的三层应用程序由下列三层组成:表示、域和数据源。即便像这么简单的事物 也需要经过很多的努力才能实现 Layered Application 模式所具有的优点。规范模型的增强版本在 Layered Services Application 中讨论。
Martin Fowler 已发现在表示层和域层之间以及域层和数据源层之间使用调解层有时会很有用。有关详细信息,请参阅 Fowler 撰写的 Patterns of Enterprise Application Architecture一书。
测试考虑事项
Layered Application 在下面几个方面增强了可测试性:
对于企业应用程序体系结构而言,将其解决方案组合成下列三层是很常见的:
Layered Application 具有下列优缺点:
优点
缺点
对较低级别接口的改变可能会渗透到较高级别,尤其是在使用了松散的分层方法的情况下可能性更大。