技术开发 频道

Programming WCF Services:面向服务概述

    通信协议

    如果组件被跨进程或跨机器边界部署,则组件将依赖于远程调用、传输协议以及编程模型要素(例如可靠性与安全性)的实现细节。

    通信模式

    组件可以被同步或异步调用,也能够联机或断开调用。一个组件能够以上述的各种方式调用,但应用程序必须知道准确的选项。

    版本控制

    在编写应用程序时,可以使用一个版本的组件,而在发布产品时使用另一个版本的组件。处理版本冲突的问题会导致应用程序依赖于它所使用的组件。

    安全

    组件需要对它们的调用者进行验证与授权。那么,组件如何才能知道它所使用的安全权限,以及用户所对应的角色?不仅如此,组件还需要确保来自客户端的通信是安全的,而对客户端施加确定的限制会反过来增加组件与组件安全之间的耦合度。

    COM与.NET都试图采用一些技术解决上述提及的部分(不是全部)问题,例如COM+以及企业服务(相似的,Java使用J2EE),但事实上,这些应用程序都被淹没在大量的公共基础功能实现中。在正常规模的应用程序中,大量的工作、开发以及调试时间都花费在实现这样的公共基础功能上,而不是关注业务逻辑与特性。事情更加糟糕的是,终端用户(或者开发经理)很少去关注这些公共基础功能(与业务特性相对),而开发者却没有足够的时间去开发健壮的公共基础功能。而且,大多数公共基础功能的解决方案都是专有的(这意味着无法重用、迁移与租赁)、低劣的,因为大部分开发者都不是安全专家,也不是同步处理专家,开发者也没有时间与资源专门开发这些公共基础功能。

    面向服务

    如果我们仔细阅读了刚才概述的软件工程发展简史,就会注意到这样一个模式:每个新的方法学与技术都会融合前一代技术的优点,并致力于改善前一代技术的缺陷。然而,每个新产生的技术又会面临新的挑战。我这里所谓的现代软件工程,就是对过去技术的去芜存菁,降低耦合程度。

    不同的是,耦合虽然糟糕,它却是不可避免的。一个绝对解耦的应用程序毫无用处,因为它不具有任何价值。开发者只能通过耦合其它内容,才能为系统添加职责。编写代码的行为就是将两个内容关联起来。真正的问题是耦合的范围究竟有多宽。我相信世上只存在两种类型的耦合。好的耦合仅限于业务层的耦合。开发者通过实现系统用例或特性,将软件的功能结合起来,完成对职责的添加。坏的耦合则将所有的内容都集成在一起。.NET与COM存在的问题,不是概念上的错误,而是基于开发者必须编写大量的公共基础功能这一事实。

    正是认识到过去的问题,在2000年末,面向服务方法学作为应对面向对象以及面向组件缺陷的解决方案呈现在人们眼前。在面向服务的应用程序中,开发者只需要关注于业务逻辑的编写,以及通过可交换的、可互操作的服务终结点暴露业务逻辑。客户端调用这些终结点,而不是服务代码或者它的实现包。客户端与服务终结点的交互基于标准的消息交换,服务发布各种标准元数据,描述服务的功能,以及客户端调用服务操作的方式。元数据就是服务,相当于C++的头文件,COM的类型库,或者.NET程序集的元数据。服务的终结点是可重用的,在交互的约束(例如同步、事务以及安全通信)下,服务是与客户端兼容的,而与客户端的实现技术无关。

    从多个角度看,服务都是组件的一个本质上的飞跃,就像组件是对象的一个本质上的飞跃一样。在软件行业中,面向服务是我们目前所知的构建可维护的、健壮的以及安全的应用程序的非常好的方案,也是最可行的方案。

    在开发面向服务应用程序时,我们能够实现服务代码与客户端使用的技术与平台的解耦,也与并发管理、事务传播和管理以及通信可靠性、协议和模式无关。总的来讲,实现从客户端到服务的消息传递的安全,就是对调用者的认证,它属于服务范围之外。服务根据需求仍然要实现服务自身的本地授权。在大多数情况下,客户端并不知道服务的版本:只要终结点支持客户端期望访问的契约,客户端就不用考虑服务的版本。为了处理客户端与服务之间传递数据的版本兼容,面向服务同时还构建了版本兼容的标准。

    面向服务的价值

    由于客户端与服务之间的交互是基于行业标准的,这个行业标准包括了保障调用安全的方式、传播事务流的方式以及管理可靠性的方式等等。我们也可以使用现有的这些公共基础功能的实现。这就保证了应用程序的可维护性,因为应用程序与准确性无关。即使公共基础功能发生演化,应用程序也不会受到影响。面向服务的应用程序是健壮的,因为开发者能够使用可用的、已验证的、通过测试的公共基础功能。同时也提高了开发者的效率,因为他们可以将更多的时间投入到功能特性的实现,而不是这些公共基础功能。面向服务的真正价值就是:允许开发者从代码中抽取出公共基础功能的实现,更多地关注业务逻辑和需要的功能特性。

    面向服务还包括许多广受欢迎的价值,例如跨技术的互操作性,就是核心价值的体现。虽然不借助于服务,我们也能够实现互操作性,但直到面向服务的诞生,才能够应用到实践中。两者的区别在于后者能够通过已有的公共基础功能为开发者提供互操作性。编写服务时,通常不用考虑客户端执行在什么平台上,因为面向服务完全实现了无缝的互操作性。面向服务应用程序所能提供的不仅仅是互操作性,它还允许系统跨越边界。其中一种边界就是技术与平台的边界,跨越这样的边界则完全体现了互操作性。但是,边界可能还存在于客户端与服务之间,例如安全与信任边界、地域边界、组织边界、时区边界、事务边界,甚至是业务模型边界。无缝地跨越这些边界是可能的,原因在于基于消息的交互标准。例如,保障消息安全的标准,建立客户端与服务安全交互的标准,即使交互双方存在于不具有直接信赖关系的域(或站点)中。事务标准允许客户端的事务管理器将事务传递到服务端的事务管理器,并让服务参与到事务中,即使两个事务管理器从来没有直接登记彼此的事务。

    面向服务应用程序

    一个面向服务应用程序只是简单地将服务组合到一个单一逻辑的、整体的应用程序(参见图A-1)中,这类似于聚合了对象的面向对象应用程序。

图A-1 面向服务应用程序

    应用程序自身可以将组合服务公开为新的服务,就好像一个对象可以由多个小的对象组成一样。

    在服务内部,开发者仍然使用传统编程的概念,例如特定的编程语言,版本,技术与框架,操作系统,API等。但是,服务之间则必须使用标准的消息与协议、契约以及元数据交换。

    应用程序中的不同服务全部可以放到相同的位置上,或者分布放到企业网或互联网上。它们也可以来自于多个开发商,使用各种不同的技术与平台进行开发,版本独立,甚至执行在不同的时区。所有的这些公共基础功能特性对于在应用程序中与服务交互的客户端而言,都是隐藏的。客户端发送标准消息到服务,两端的公共基础功能通过消息以及与平台无关的传输型表示形式进行转换,并对客户端与服务之间存在的区别实现封送(Marshal)。

    既然面向服务框架为了将服务连接在一起,提供了现有的公共基础功能,那么服务的粒度越小,就越能够有助于应用程序对这些基础设施的使用,开发者所要编写的公共基础功能就越少。在极端的情况下,每一个基本的类都应该是服务,以便于最大程度地利用现有的互联性,避免编码实现公共基础功能。理论上讲,它能够轻松地实现事务型整数,安全字符串以及可靠的类。然而实际上,粒度过于细化会影响到使用的框架(例如WCF)的性能。我相信随着时间的流逝,以及面向服务技术的发展,服务边界的内聚性会越来越强,服务的粒度会越来越小,甚至于每个基本的构建模块都可以成为服务。显然,这是历史的发展趋势,那就是通过方法学的改进以及抽象,以性能换取效率的提高。
0
相关文章