技术开发 频道

详解SOA五种基本架构模式

模式五:边界组件

    最后一个基本模式是边界组件模式。称其它模式为基本模式是因为它们有很大的通用性。但边界组件模式不同,称它为基本模式是因为这是一个实现其它模式的平台。由于边界组件模式是实现其它模式的一个步骤,具体的示例都是适应于在这个边界组件上构建的模式的,所以很难想象一个具体的示例来展示它的必要性。不过,我会尝试通常几个简单的例子和这些例子之间的共性来介绍边界组件。

    问题

    场景1

    我们曾经为一家公司开发了一个海军C4I平台(Military Naval C4I platform)。这个平台有一些可以重用的服务。比如,核心服务之一提供了标准的中央目标视图。平台上第一套工具使用了TIBCO Rendezvous消息设施。后来需要更换完全不同的技术(WSE 3.0 )。这两套工具都使用相同的业务逻辑,但是实现技术不同。

    场景2

    在另一个项目中(在工作流化模式中提到过),一家移动公司经常需要在一个处理订单的服务中引入新的应用和销售方案,比如朋友和亲情、晚间话费等。由于详细变动都是XML相关,因此这个服务接口是非常稳定的,但是业务逻辑却要为适应新方案而经常变动。

    这是一个与场景1截然相反的场景;这里的接口与技术是不变的,而业务逻辑是变动的。

    场景3

    最后一个场景是许多项目中常见的一种情况。通常系统里会有多个服务。虽然每个服务处理各自不同的业务,但所有这些服务都要执行一些常见的任务,比如在处理请求之前要确认请求是经过验证的,保存审核条目等等。

    在这个场景里,我们遇到了一个不是与单个服务直接相关但在各服务之间重复性却是最高的功能——因为即使一个服务是处理订单的,另一个服务是面向顾客的,其记录请求的代码都是基本一样的。

    这些场景的共性是每个服务都涉及多个问题(业务逻辑、技术、记录等)。正如我们所见到的,所有这些问题都必须可以根据情况进行变更而不依赖于其它的问题——我们需要实现这种灵活性。因为我们的问题是:

    如何让服务、技术和其它交叉问题(比如安全、记录等)等业务方面的问题可以按自己的步调变更而不产生相互的依赖性?

    最简单的(或许过分简单了)办法是不要做任何具体的变动。比如,直接把一部分逻辑当作Web服务。这对技术提供商的在线业务来说是很常见的,比如Microsoft (WCF)和 Sun (JAX-WS)提供的教程。然而,由于契约操作与业务逻辑实现直接纠缠在了一起,这给代码维护带来了极大的不便——比如,如果要支持场景1,用这种方法来替换技术可能就会非常困难。

    我们可以通过在复制服务上替换新技术来解决前面的在当前服务中替换技术的问题,这种方法也叫“自我克隆(own and clone)”。不过这也会产生维护上的问题,因为你现在有了同一业务逻辑的多个复本,因此你得改动所有复本,并且这还解决不了场景3里要在多个服务上添加记录功能的问题。

    如果什么也不做和克隆都行不通,那么我们可能要考虑分开解决各个问题。

    解决方案

    关注点分离(SoC)在面向对象的设计中是一个为人熟知的概念。其背后的基本原则是单一责任原则(The Single Responsibility Principle),或简称为SRP。SRP认为要改变一个类只能有唯一的原因,这个原因就是责任(responsibility)。我们可以在SOA中应用同一原则,把业务逻辑看作是一个责任,把其它的问题看作是另一个责任,这样我们就得到以下模式:

    附加边界组件(Add Edge Component(s)),用以实现服务并提高灵活性、分离业务逻辑与其它问题(比如契约、协议、终端技术和其它交叉问题)。

    正如图11所示,添加边界组件的主要原因就是关注点分离。边界组件可以处理所有这些交叉问题以及其它非核心业务问题。这些问题包括负载平衡、格式转换和审计。这样,服务的业务逻辑就交给了另一个专门处理业务逻辑的组件。这种分离支持所有前面提到的场景,因为分离可以允许各个部件自由调整。比如,要支持一项新技术(场景1),只需要添加一个边界组件,但是业务逻辑并不需要更换。如果要改变业务逻辑的行为,就添加一个新的使用方案(场景2),而边界组件则不需要更换。

    

    从某种意义来说,边界组件模式可以为SOA提供外观(fa?ade)、代理、和AOP模式。

    我们还要看一下如何解决场景3中服务间的交叉问题。最好的办法是进一步扩展单一责任原则,并且注意边界组件实际上是一个组件,不能把它对应于整个类型的类。比如,你可以应用管道和过滤架构类型,把多个类/组件连接到一起,各个类/组件处理特定的问题,以此来创建传入或传出的流程。比如,图12即是一个边界组件的示例。该示例中,边界组件提供了一个验证过滤器来确保消息有正确的格式。然后是一个转换过滤器把外部契约格式转为内部格式。最后是一个路由过滤器,负责把消息发送到服务的正确组件。这些组件可以在各个服务中根据需求重用,并且能够自由地进行更改。

    

    虽然从一开始就在边界组件和服务之间定义一个内部契约很有吸引力,但是实际上没有理由这么做,除非你必须支持多个外部契约(虽然实现与消费者一对一的契约非常麻烦——见PTP Integration反模式)。如果服务进展并且创建了新的契约版本,像场景1中像添加新技术,那么在需要支持外部老版本的契约时你可能需要添加内部契约。

    边界组件非常有用,我在我设计的大部分SOA项目中都引入了这个模式。本书中提到的许多架构模式也都是基于边界组件模式的扩展。

    下面我们来看看边界组件模式的技术相关问题。

    技术相关

    这一部分我们将简单的了解一下利用当前的技术实现这个模式的意义以及实现模式所涉及的技术。

    没有任何技术能够像边界组件一样自动处理那么多问题。不过乐观的说,没有任何技术会影响你实现边界组件模式,而且某些技术最终将帮你解决一些让你困惑的问题。

    比如,JAX-WS或Windows Communication Foundation (WCF)实际上已经为你实现了边界组件模式,但它们只处理底层的问题,也就是它们称为绑定(binding)的东西。这些问题是在各种WS*标准中提到的;比如WCF可以处理MTOM encoding或安全问题。然而,你还是需要自己编写高层的问题,比如路由和契约转换。这一点我在上面已经提到过。

    还可以使用一种有趣的技术,是称为Restlet的Java引擎。Restlet有一些内置的类,使其成为实现边界组件模式的优秀范例。

    边界组件范例——Restlet引擎

    Noelios Consulting公司的Restlet引擎是一个用以实现RESTful服务的Java库,它有一些内置类(比如filter和router),可以让我们很方便地构建边界组件。请看图13的示例。

    

    图13是一个在订购服务上的可行的边界配置。这个订购服务的契约有两种操作:getLast,返回上一次的订单;和getAll,返回某个客户所有的订单。但是在实际调用业务逻辑之前,我们得先记录它,处理它的状态和情况,然后确定使用了正确的主机,最终调用正确的业务功能。添加一个边界组件可以让我们获得以上效果,并且不会影响到只处理业务请求的业务逻辑。

    下面是上述配置的部分代码。

    例2:使用Restlet定义的边界组件部分代码

Builders.buildContainer()
    .addServer(Protocol.HTTP, portNumeber)
    .attachLog("Log Entry")
    .attachStatus(true, "webmaster@mysite.org", "http://www.mysite.org")
    .attachHost(portNumber)
    .attachRouter("/orders/[+")
    .attach("/getAll$", getAllRestlet).owner().start();
    .attach("/getLast$", getLastOrderRestlet).owner().start();

    现在所有的技术都支持边界组件模式,有些甚至已经在内部实现。

    质量属性场景

    这一部分是从需求的角度讨论使用模式的架构效益。大多架构需求是通过使用场景表现的质量属性(可扩展性、灵活性、性能等)来描述的。这些场景也可供其它可以应用模式的情况参考。

    由边界组件模式与许多质量属性有关。这些属性大多是由共同使用边界组件模式和其它模式产生的结果。然而,有两个质量属性是直接与边界组件模式相关的。第一个是灵活性——增强服务的适应性,提高服务的外部属性,并且不会影响到业务逻辑。第二个是易维护性——关注点分离(SoC)使各组件的行为更易于理解。回想一下上面三个场景——在当前服务中添加新技术、在不改变契约的前提下改变业务行为、以及迅速解决交叉问题——通过边界组件,我们可以在不影响方案的其它部分(或者至少将影响最小化)的情况下解决问题。下表列出了几个使用边界组件的示例场景。

质量属性(第一层)质量属性(第二层)场景示例
易维护性向后兼容性随着契约的变化,服务应该能够使用老版本的契约为消费者提供支持(至少前两个版本)
灵活性扩展点在将来一年之内,客户将需要SOX compliance和董事会的审计制度

     边界模式是SOA最基本的架构模式。

总结

    最后,来看看我们讨论过的这五个构建服务的SOA基本模式。这些模式分别为:

    * 边界组件:将接口(契约)从实现中分离出来以取得灵活性与可维护性

    * 服务托管:使用通常包装器来托管服务实例并重用

    * 主动式服务:在服务中使用至少一个独立线程来启动

    * 事务处理服务:处理事务内部的消息并妥善处理故障

    * 工作流化:在服务中添加工作流以提高灵活性

    本文内容取自曼宁出版社将于2009年2月出版的《SOA模式》一书(http://www.manning.com/rotem)。

 

1
相关文章