使用模式创建一个面向服务的组件中间件(一)

日期: 2008-08-11 作者:Jim Siddle 来源:TechTarget中国 英文

  研究某个中间件项目中应用的多种模式的模式故事,了解模式是如何应用的,每种模式的成功程度如何,以及这些模式间的交互和关系。如果您是模式的使用者、编写者或理论工作者,这篇文章将会适合您。


  引言


  在本文中,您将了解面向服务的组件中间件在用于资源有限的语音设备时,在设计阶段所应用的模式。它涵盖了项目的问题上下文,并被看成是一组决定因素,是对相关体系结构远景的一个简要概括。您还会得到一份描述,其中介绍了一些被用来解决问题和创建软件体系结构的模式,以及它们的应用方法和相互关系。


  本文重点关注在某一特定项目中应用各种模式的具体经验,而不是描述通过应用模式来解决问题的理想化方法。本文假定您已经熟悉了所讨论的各种模式。


  下列关于面向服务的体系结构的定义摘自Wikipedia,并被本文所采用:


  “面向服务的体系结构(SOA),这个术语是指一个用来实现软件体系结构的业务驱动的方法,它支持将业务集成为一组有联系、可重复的业务任务或‘服务’。服务是指可重用的自包含软件模块,具有经过良好定义的接口,并独立于应用程序和运行它们的计算系统。”


  项目团队对SOA概念的理解体现在这一定义中。对于项目而言,重要的SOA关键特性有:可重用的自包含软件模块,具有良好定义的接口,以及平台独立性;因此也产生了“面向服务的组件中间件”这个术语,用以描述这个系统。在这种情况下,平台独立性是必不可少的,它可以在各种可选平台上实现代码的重用。


  问题上下文


  模式被应用在针对多种商业语音设备的软件开发项目中,这些设备的资源是有限的。它的主要目标之一是创建新的软件体系结构和面向服务的软件组件,这些软件组件可以在组织内部未来的软件开发项目中重用。这个目标是本文的重点;它是项目中各种模式应用背后的驱动因素,可以使您在早期阶段中将重点放在体系结构的开发上。出于保密因素,项目中的其他目标不会在此处予以描述。


  有几项专用于语音领域的可重用服务可以在项目的初始阶段被标识出来,为了支持这些服务,一个处于开发阶段的软件体系结构是必不可少的。必需服务的典型示例有:


  ·允许在本地的用户个人目录中或通过远程企业目录应用程序进行电话目录查询。
  ·将“同伴”的存在信息提供给本地的语音应用程序,并将用户的存在信息传播给远程企业应用程序。
  ·记录和管理与语音有关的用户动作和相关事件,供以后的用户和管理人员参考。


  这些目标背后的几个原因,在表1中描述为定义问题上下文的决定因素。



  表1. 用来定义问题上下文的决定因素


  项目背景


  在项目初始阶段使用的开发流程是十分灵活的,它是一个主要基于Scrum和极限编程的流程。该流程是由用户场景驱动的,并以体系结构为中心,它的重点在于体系结构模式、并发和优化模式,以及资源管理模式的应用,在《Pattern Oriented Software Architecture》系列丛书中有介绍。(请参见参考资料。)


  一般来说,会根据每次迭代的需求,在迭代的开始时调查并选择候选模式。本文中所述的一小部分模式会被认为是在先前已经应用了。(这些模式用来为跨模式的体系结构提供一个完整的视图。)


  根据需求列表建立的概略体系结构远景是模式选择中的驱动因素。架构师会在模式选择和粗略的预先设计中为团队提供指导,模式被作为迭代予以应用,并通过测试驱动的开发和持续的集成推进迭代过程。在迭代结束时,会根据接受性测试(该测试也将成为迭代的输入),对实现的结果加以证明。


  最初的团队结构是围绕以下部分所述的体系结构构建块建立起来的。在本文中所述的绝大多数模式都是由一个团队应用的,该团队负责创建面向服务的组件中间件和初始服务。


  大多数开发选择的编程语言为C++。


  术语和体系结构远景


  软件体系结构远景应针对资源有限的语音设备创建一个面向服务的组件中间件。下面列表列出了在项目开始阶段引入的关键概念或术语。


  服务


  封装了业务逻辑的可重用软件资产,一般由粒度较小的组件(如类)组成。


  服务容器


  管理服务生命周期、通信和调用;可以使服务将重点放在业务逻辑上。


  服务接口


  由某个特定服务公开的接口,它表示可供服务客户机调用的功能。在预想中,它会支持本地和远程调用。


  服务总线


  用于一般目的的服务通信机制,提供位置透明性和基础通信的封装。


  平台抽象


  一组可提供平台独立性的接口。


  图1. 体系结构远景概述




 
  图1 提供的简要概述介绍了体系结构远景中的几种概念是怎样互相联系起来的。


  解决方案


  这一部分将介绍:


  ·项目中应用的各种模式。
  ·选择它们的理由。
  ·针对模式应用和模式间的交互(或关系)展开的讨论。


  建立各层


  分层 模式为软件体系结构提供了总体的基础结构,以支持项目的产品线开发策略。这一模式是上述体系结构远景的一部分,它从一开始就为团队的思维过程建立起一个框架。


  选择分层模式,以便将高价值的可重用服务和服务相关代码移植到服务层中,只能通过与 平台 层的严格接口来使用核心平台功能。应用程序层中已移植的代码和平台层,都是特定于每个计算平台的。


  这一模式对项目的其他部分有深远的影响。已经建立的各层为其后的所有实现决策提供了一个框架。与下列的大多数模式不同,该模式实际上并没有与之相关的代码;它针对以后的实现形成了一个基本的概念化框架。


  下面是与分层模式相关的两个具体构件:初始团队结构和初始配置管理数据存储结构。两者都是围绕着已经建立的层形成的,在项目中,这种做法为分层赋予了更大的实质性意义。这是一个逻辑化的方法,在产品线开发策略中,会随时间的推移,围绕不同的体系结构块建立和解散不同的团队,且不同的块可以被访问、修改,并在软件的生命期间内以多种方式使用。”Conway定律”和相关的组织模式,如组织遵循模式能使您深入了解团队的结构是如何与体系结构联系起来的。


  有趣的是,稍后在项目中还会第二次应用分层模式。由于在先前建立的层和配置管理数据存储(以原始分层为基础)中观察到的某些其他体系结构的抽象过于庞大,会导致基础设施出现技术问题。服务层被拆分为(自上而下)业务服务、基础设施服务和框架。除了原始平台层之外的所有分层都并不严格;这些分层是以软件要素的可观测逻辑化分组为基础的。在应用层内部也有类似的拆分工作,分为应用程序、应用程序框架和表示层。


  分层的第二项应用是作为最终的、基于UML包的方法的中间步骤。由模式的第二项应用引入的各层会被相继转换为包,这些包经过显式定义,具有独立性。这可以对各层之间的依存关系进行更为精确的表示和分析。


  引入分层不会使项目出现可觉察的性能问题,这主要是因为目标设备硬件有处理相关开销的功能。这并非对所有场景都适用;如果最终的软件应该在资源有限的环境中运行,那么您在应用这种模式时必须小心从事。


  在下面的讨论中,各种模式主要应用在框架的上下文、基础设施服务和业务服务中,只有包装外观模式是个例外,它被应用在平台层的上下文中。


  对平台进行抽象


  下一个步骤是引入平台独立性。如果没有平台独立性,要在不违反体系结构远景的核心原则的前提下做任何事情都是很困难的。包装外观方法被用来封装针对特定主机的低级别功能、数据结构,以及对遗留代码和第三方代码的调用。


  包装外观模式的应用,使定义纯粹的操作系统抽象成为可能,可以按照需要,通过语音产品的开发,针对特定的操作系统实现这些抽象。某些已知具有可维护性问题的遗留软件组件可以集成到项目中。为这些组件创建包装外观,会隐藏遗留组件间复杂的交互细节,并提供了一个抽象,使新旧代码不致混淆。类似的方法也可用于某些第三方软件组件。


  包装外观中所含的遗留代码的典型示例是一组相关模块,这些模块负责与远程语音设备管理平台进行交互。操作系统的示例包括文件访问权和网络访问权。


  对操作系统、遗留代码和第三方代码的抽象为平台独立性打下了基础。这一方法的结果是出现了支持和开发抽象的需求。如果项目具有可迭代性和增量性,那么只会在需要的时候添加抽象,但这意味着为了创建抽象必须继续投入时间和精力,在某些情况下,在使用抽象之前还应重写代码。


  如果在一开始就引入了平台抽象的概念,就能更容易地推动项目期间抽象的创建和维护工作。


  管理服务生命周期


  在建立了平台独立性之后,现在应该将服务引入系统了。创建和删除服务看来是一个合理的起始点。组件配置器,此模式在项目的早期即被选中,用来管理服务生命周期,该模式的应用范围很广(如该模式中所述)。


  在组件配置器的初期实现中,提供了一套服务创建和始初化的机制,并为将来迭代过程中服务的重新初始化和关闭打下了基础。当组件配置器实现发出提示时,由服务执行初始化的典型示例有:


  ·服务发现
  ·订阅其他用于事件通知的服务
  ·平台和第三方资源的创建和初始化,如网络套接化或电信协议栈。


  稍后,组件配置器的角色会得到扩展,以发现和管理服务间的连接。项目的体系结构目标是将服务与基础通信细节(如传输、消息协议、位置等等)分离。该实现将得到扩展,提供一套动态查询机制,服务可以调用这一机制以发现其他服务。


  组件配置器的实现将“发现”责任的一部分指派给系统中的另一个要素,但根据事后反思,在此区域内指定责任的做法是不合适的。服务间的连接应当单独管理,但由于组件配置器实现在系统中居于中心地位,修改它的责任是很容易的。这会使相关的类更加难以理解;创建一个单独的类,让它负责管理服务连接,并可以在必要时咨询组件配置器,这种做法可能更好。


  幸运的是,如果责任被错误地分配给少量的类,我们还可以限制它的影响,方法是将封装上下文对象和分离上下文接口应用于组件配置器实现,有选择地公开发现方法。组件配置器实现经过修改,以实现一个服务上下文接口,使用服务的初始化方法,可以把上下文接口传递到这些服务。类似地,在实现框架上下文接口后,可以将其传递给几个不同的框架层要素,以公开相关的方法。


  根据事后反思,框架上下文接口的命名和定义过于宽泛,作为接口传递目标的框架层要素也显得太多了。如果对这个上下文接口进行拆分,而不是使之成为一个供各个框架层要素使用的全方位接口,这种做法会更好。


  引入服务通信和位置透明性


  接下来的问题是,服务应当彼此通信,而且某个服务不应知道另一个服务的位置。


  这两个问题同时得到了解决。引入的服务总线子系统将命名端点间的通信封装起来。这是实现服务间通信的一个关键步骤,它能在开始时创建命名服务总线端点的实例,以便与其他服务通信。这种方法是从Qt”CopChannel”机制(? TrollTech)和中介模式借鉴而来的。该实现是模式中的消息传递中介系统的一个变体实例,如POSA模式文档中所述。


  中介模式的初期实现提供了进程内部和进程之间的通信。其结果是,服务可以通过组件配置器轻易地部署到不同的进程中去,这在以后根据操作的重要性划分服务时会被证明是有用的。例如,一个处理关键语音事件的服务与用来收集非关键性能统计数据的服务,两者处于不同的进程中。


  稍后会添加一个桥接以启用远程通信,这将使中介实现得到扩展。体系结构中的这个要素的初始设计并没有直接借鉴中介模式,而是独立构思出来的。稍后项目中的桥接角色和有问题的要素之间的相关性会被标识出来。这一系列事件对桥接角色与系统中其他部分的融合有不利影响;如果整个项目团队对中介模式有更细致的了解,可能会减轻这一影响。


  有些远程应用程序会调用带有桥接的服务,这样的例子包括测试工具和语音设备管理应用程序。在本项目中没有对使用桥接的对外服务调用进行阐述。


  建立服务交互


  在迄今为止的系统中,各项服务都可以与彼此对话,但服务并不理解它们之间的交互性。


  客户机-服务器的交互是作为系统整体行为的中心建立起来的,服务可望具有客户机和服务器的双重身份。系统的其他要素(如应用程序表示逻辑)只能成为客户机。


  引入的客户机-服务器交互有两种类型:同步和异步。如果服务总线子系统是纯粹基于消息的,而且支持某种用来等待传入消息的读取方法,它将自动提供这两种类型的交互。


  同步交互的一个典型例子是由某个服务发送给另一个服务的订阅请求,发出请求的服务必须在收到成功的响应消息之后才能继续。接下来的事件通知则是一个典型的异步交互示例。


  除了在服务间建立交互模式之外,客户机-服务器应用程序服务器还支持将服务划分为易于理解的客户机和服务器角色。


  一旦在客户机和服务器间建立了异步交互,会应用异步完成令牌模式,以使客户机能有效地处理异步响应。起初这种模式被尝试着应用在系统基础设施上,但后来没有继续这样做,因为该模式更适合与服务进行直接交互,而不是用来支持基础设施。完成这一活动,为体系结构内的模式提供一般性支持,这是合理的做法。模式不容易被服务开发人员理解,因此只在较少的服务交互中得到应用。

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

相关推荐