Jakarta main

Avalon main

About


章节


原文链接


Printer Friendly


中文译者


分解一个系统

您是如何决定由哪些东西组成一个组件的? 关键是定义您的解决方案所需的设施,以便能有效率地进行操作。

我们将使用一个假想的业务服务器来展示如何识别和确定服务与组件。在我们定义了一些系统用到的服务之后,我们将以这些服务中的一个为例,定义该服务所需的不同组件。我的目标是传递给您一些概念,这些概念有助于您把您的系统定义成可管理的部分。


系统分析——识别组件

尽管提供一个完整全面的方法学不是本篇的范围,我还是愿意讨论几点问题。我们将从组件和服务的面向实现的定义开始,然后提供一个实践的定义。

组件

一个组件是一个工作接口和该工作接口的实现的组合。使用组件提供了对象间的松耦合,允许改变实现而不影响使用它的代码。

服务

一个服务由一个或更多的组件组成,提供了一种完整的解决方案。服务的例子包括协议处理器、任务调度器、认证和授权服务等等。

尽管这些定义提供了一个起点,但它并没有提供一个完整图景。为了把一个系统(定义为一组设施,组成一个项目)分解为必要的组成部分,我建使用自顶向下的方式。采用这种方式可以在您了解到底有哪些设施之前,避免陷入到细节的泥潭中。

确定您的项目范围

您的项目预期完成什么功能,一开始您总要有个大致的想法。在商业世界里,初始工作说明(initial statement of work )就是完成这项工作的。在开放源代码的世界里,这通常是由一个想法或一个脑力激荡的过程完成的。我想不论如何强调具备一个项目的高层视图的重要性都是不过份的。

很明显,一个大项目将由许多不同的服务组成,而小项目只有一两个服务。如果您开始感到有点不知所措,只需提醒自己大项目实际上是一把大伞下的许多小项目。最终,您将能理解整个系统大的图景。



工作说明:业务服务器

业务服务器(Business Server)是一个假想的项目。出于我们讨论问题的目的,它的功能是处理销售订单,自动向客户发出账单,并管理存货控制。销售订单到达时必须得到处理,通过某种类型的事务系统。在销售订单填写30天后,服务器自动向客户发出账单。库存由服务器和工厂或仓库的当前库存量同时来管理。该业务服务器将是一个分布式系统,每个服务器将通个一个消息服务来与其它服务器通信。


发现服务

我们将使用这个Business Server项目来发现服务。考虑上面的过于概括性的工作说明,我们立即可以看到项目描述中定义的一些服务。服务的清单可被分成两大类:显式的服务(可以从工作说明中直接导出的服务)和隐式的服务(根据相似的工作发现的服务,或对显示服务起支持作用的服务)。请注意,实现系统的公司不必亲自开发所有的服务——有一些可作为商业解决方案购买。在那些情况下,我们可能会开发一个封装层(wrapper),以便我们能够以确定的方式与商业产品实现互操作。实现系统的公司将构建大部分的服务。

显式的服务

从工作说明中,我们可以快速导出一些服务。但这种初始分析并不意味我们的工作已完成,因为某些服务的定义需要其它服务的存在才能保证。

事务处理服务

工作说明明确指出“销售订单到达时必须得到处理 ”。这表明我们需要有一种机制能够接受销售请求并自动地处理它们。这与web服务器工作的方式相似。它们接收到对资源的请求,进行处理并返回一个结果(如HTML页面)。这被称作是事务处理。

完整地说起来,存在不同类型的事务处理。这种一般性的事务处理服务极有可能必须分解为一些更特殊的东西,如“销售订单处理器“。具体方法取决于您的服务的通用性。在可用性和可重用性之间存在一种平衡。服务越是通用,它就越可重用。通常它也就越难于理解。


调度服务

在某些情况下,当事务完成,过了一段特定的时间之后,必须调度某个事件。而且,库存控制过程必需能周期性地开出采购订单。因为工作说明中指出“ 在销售订单填写30天后,服务器自动向客户发出账单” ,所以我们需要一个调度服务。所幸的是Avalon Cornerstone为我们提供了一个,这样我们就不必再自己写一个了。


消息服务

工作说明中指出,在我们的分布式系统中“每个服务器将通个一个消息服务来与其它服务器通信“。让我们来考虑这个问题,有时用户需要一个特定的产品或一种他们想用的方法。消息服务是利用其它公司产品的一个首选例子。极有可能,我们将采用Java Messaging Service (JMS) 来作为Messaging Service的接口。因为JMS是一个标准,它的接口不大可能短期内发生变化。

从实践经验上来说,一个定义良好的面向消息的系统在可扩展性方面要强于面向对象的系统(如EJB)。可扩展性更好的一个原因是消息通常并发内存开销较小。另一个原因是它更容易把消息处理的负载分散到所有服务器上去,而不是把所有的处理集中在少量的服务器集群上(甚至是在一台服务器上)。


库存控制服务

尽管这不是一个教科书上的经典服务,但它是这个系统的一项需求。库存控制服务固定地监视工厂或仓库存货的记录,当存货开始不足时触发一些事件。



隐式的服务

运用在过去系统中获得的经验,将系统更进一步分解出其它服务,将得到没有明确指出但又是系统需要的一些服务。因为篇幅关系,我们将不做全面地分解。

认证和授权服务

认证和授权服务没有在工作说明中明确地提到,但是所有的业务系统必须认真考虑安全性。这意味着系统所有的客户端都必须经过认证,用户的所有行为都必须经过授权。


工作流自动化服务

工作流自动化是企业系统中的一个热门开发领域。如果您不使用第三方的工作流管理服务器,您就需要自己写一个。通常工作流自动化所做的是使用软件系统来安排贯穿公司业务过程的任务。更多的信息请参考Workflow Management Council的网站http://www.wfmc.org/


文档中心服务

作为一个任务的当前状态信息,"文档中心"这个词的定义很不精确。换言之,当公司接到一份购买订单时,我们的系统需要能够存储并重新调出购买订单信息。出账单和系统中其它任何过程,从库存到新的用户请求都有同样的需求。



小结

我希望Business Server项目的服务的例子可以帮助您发现更多。您会发现,当您从较高的抽象层逐渐转向较低的抽象层时,会发现需要更多类型的服务,如用于在一个打开端口上处理请求的连接服务。我们定义的某些服务将通过第三方的系统来实现,如消息服务和工作流管理服务。对这些服务来说,使用一个标准接口是最符合您的利益的,这样您可以在以后更换供应商。有些服务实际上是由多个服务组成的大服务。有些服务Avalon Excalibur或Avalon Cornerstone中已经提供了。

在发现一个系统中的服务时,应该牢记的一件事是:一个服务应该是一个高层子系统。这将有助于您通过分析师团队来定义组件。因为我们已识别出了主要的服务,您可以让多个个人(或团队)并行地分解每个服务。子系统边界也定义良好,发生重叠的可能性很小。如果您决定进行并行分析,您应该回过头来识别通用的组件,以便能够尽可能地重用。

UML Diagram for the Business Server
Berin Loritsch, 2001
  • Berin Loritsch, 2001


发现组件

我们将以前面提到的文档中心服务为例来说明识别合适的组件的过程。为讨论方便起见,我们现在来列出文档中心服务的需求。文档中心将采用一个数据库来作为持久存储,对客户端授权,在内存中缓存文档。

组件的实践性定义

当我们谈论组件时,您考虑问题的角度应该是:我的服务需要操作哪些设施?Avalon相信将系统投影(cast)的概念。系统的开发者会面对一个组件的职责列表,组件则被称为它的角色(role)。

什么是角色?

角色的概念来自剧院。一部戏剧、音乐剧或电影片都会有一定数量的角色,由演员来扮演。尽管演员似乎从不短缺,角色的数量却是有限的。演出的脚本 定义了角色的功能或行为。如同剧院里发生的一样,脚本决定了您如何与组件交互。考虑系统中的不同角色,您会将组件的投影为角色,并与之对话。

一个角色是一类组件的契约。例如,我们的文档中心服务需要操作数据库。Avalon Excalibur定义了一个组件,符合"Data Source"脚色的需要。在Excalibur中有两个不同的组件,都能满足该角色的需要。 具体使用哪一个取决于服务所处的环境,但是它们都满足相同的契约。大量基于Avalon的系统对每个角色将只用到一个活动的组件。脚本就是工作接口:其它组件与之交互的接口。

在确定组件的接口时,必须有确定的契约并牢记在心。契约规定了组件的使用者必须提供什么,以及组件生产出什么。有时在契约中必须包括使用语义。一个例子是临时存储组件和持久存储组件之间的区别。当接口和协议定义好之后,您就可以致力于实现。



怎样算是一个好的候选组件?

在我们的文档中心服务中,我们已识别了四个可能的组件:DataSourceComponent (来自Excalibur)、 Cache、Repository、Guardian。您应该寻求那些很可能有多种实现的角色,与这些实现的交互可以无缝地进行。

通个这个例子,您会发现一些情况下您需要使用可替换的设施。大多数情况下,您只会用到该设施的一种实现,但您需要能独立地升级它而不影响到系统的其它部分。其它情况下,您需要根据环境的不同使用不同的实现。例如,Excaliber定义的"Data Source"通常会自己处理所有的JDBC连接池,但有时你可能希望利用Java 2 Enterprise Edition(J2EE)中提供的设施。Excalibur解决这个问题的办法是,一个"Data Source"组件直接管理JDBC连接和池,另一个组件使用Java's Naming and Directory Interface (JNDI) 来得到特定的连接。


怎样不算是一个好的组件?

习惯于使用JavaBeans的人喜欢把所有的东西都实现为一个JavaBean。这意味着从数据模型到事务处理的一切东西。如果您用这种方式来处理组件,您可能会得到一个过于复杂的系统。把组件视为一个服务或设施的模型,而不是数据的模型。您可以有从其它资源拉数据的组件,但数据还是应该保持为数据。在Avalon Excalibur中这种哲学的一个例子是连接(Connection)不是一个组件。

另一个例子是我们前面提到的Guardian组件。可能存在的争议是,Guardian所包含的逻辑与文档中心服务太相关,不能做为一个组件用在完全不同的服务中。尽管管理复杂性有多种方式,也有多种方式让它变得灵活,但有时为它付出额外的工作并不值得。在这种情况下,您必仔细权衡您的决定。如果一个潜在组件的逻辑将被一致地应用,那么将它作为一个组件可能是有意义的。在一个系统中可以有一个组件的多个实例,它们可以在运行时进行选择。如果潜在组件的逻辑只是根据另外一个组件来确定的,也许可以把这些逻辑放到另外的那个组件中去。通过Guardian组件和Repository组件的例子,我们可以辩称Guardian太专注于Repository,不是作为一个组件来实现的。


分解文档中心服务

我们将列出将要实现的组件,以及它们的角色、根本原因和来源(如果组件已经存在的话)。

DocumentRepository

DocumentRepository是整个服务的父组件。在Avalon中,服务实现为Block,Block是一个特定类型的组件。Block必须有一个工作接口,扩展了Service marker接口。Block接口也扩展了Avalon的Component接口。请注意,Block和Service是包含在Avalon Phoenix中的接口。最后,Service从技术上说仍是一种特定类型的Component。

DocumentRepository是我们从持久存储中取得Document对象的方法。它与服务中的其它组件交互,以提供安全性、功能性和速度。这个特定的DocumentRepository会与数据库连接,在内部使用数据库的逻辑来建造Document对象。


DataSourceComponent

DataSourceComponent由Avalon Excalibur提供。它是我们获得有效的JDBC连接对象的方式。


Cache

Cache是一个短期内存中的存储设施。DocumentRepository将用它来保存Document对象,并通过一个散列算法来引用。为了提高Cache组件的可重用性,存储的对象必须实现一个Cacheable接口。


Guardian

Guardian组件的作用是基于参与者管理许可。Guardian将从数据库中装入许可规则集。Guardian将使用标准Java安全模型,以保证对特定Document的访问。



小结

到目前为止,您应该对怎样才算是一个好组件有一些认识了。例子描述了在文档中心服务中的所有组件,简要介绍了它们将完成的工作。快速浏览这个列表,它体现了将设施实现为组件而不是数据的方法。到目前为止,你应该能够确定您的服务需要操作什么组件。





Copyright ?999-2002 by the Apache Software Foundation. All Rights Reserved.