构件对象模型概览
傅贵
计算机软硬件技术特别是网络技术的飞速发展使得人们可以建造功能更强大、结构更复杂的应用。这样的一个结果是在应用系统中硬件越来越“瘦小”,而软件越来越“肥大”。
由于一个应用常常需要异种的计算机硬件平台及其相连的操作系统平台并且其功能常常需要不断的扩展,大的应用软件常常需要有跨越多个异种平台的能力并且有开放的系统结构。此外,为了提高开发速度和节省开发费用,需要最大限度地重用以有代码。因此,当今的应用软件普遍需要有良好的平台兼容性(互操作性)、结构开放性、规模可变性(可扩展性)及代码重用能力等。
另一方面,在传统的系统开发技术下,庞大的软件使得开发越来越难、开发周期越来越长、维护费用越来越高并且功能的扩展危险而难行。应用系统严重依赖于操作系统和特定的网络服务因而开放性很差。开发者为每种不同的应用环境(本地应用、网络应用、不同操作平台的应用)开发不同的代码。如为解决这些问题,国际上成立了许多标准化组织来对系统和处理方式加以标准化,但这只是增强软件可操作性和重用性的一种权宜之计,并不能彻底解决问题。在这种情况下,出现了具有互操作能力和可重用能力的构件对象设计模式和具有分散和联合处理能力的开放分布式处理系统。
构件技术与构件对象模型基本概念
组合软件模型是新一代软件技术发展的标志,它的提出很自然,为了提高软件生产力、不草率地开发应用程序、设计开发人员应尽可能地利用可重用的软件构件、组装构造新的应用软件系统。追根求源,由软件模块构件组织合成软件的思想早在
70年代就已提出了,函数就是一种构件,函数通过参数来适应不同应用需求的变化,Ada语言的模块package就是一种构件,实现了内部细节掩藏,模块通过接口规范说明进行连接和组装,package还提供了类属机制,使模块通过类属参数,适应不同应用需求的变化。但是,传统软件系统结构的局限性,以过程为中心设计的功能模块,其扩充和复用的能力都较差,对模块进行应用重组的困难很多。从80年代开始的面向对象技术的研究,使组合软件又萌发出新的生命力。面向对象的软件,以数据为中心设计,对象类既具有模块的封装性和类属等特性,还具有继承特性,极大地提高了类的可扩充性和可再用能力。对象类较之于传统软件的功能模块而另具有的主要优点是:最早大量使用面向对象技术的是
OO(面向对象)的编程语言,它具有上述前三个优点。但OO中的对象是源代码级的,它没有也不能统一对象间相互作用的工作机制。这意味着它不能克服以下的缺点:与
OO编程语言不同,构件技术是一种更高层次的对象技术:它是独立于语言和面向应用程序的, 它只规定构件的外在表现形式,而不关心其内部实现方法;它既可用OO编程语言实现,也可用非OO的过程语言实现。只要遵循构件技术的规范, 各个软件开发商就可以用自己方便的语言去实现可被重用的构件, 应用程序的开发人员就有可能实现在计算机硬件领域早已实现的梦想:挑选构件、组合新的应用软件。构件模型由构件(Component)与容器(Container)两种主要成份构成。所谓构件是指具有某种些功能的独立软件单元,是一种软件“IC”,它的最重要的特性是可重用性。,构件的范围相当广泛,小的构件有像按钮之类的GUI元素,中等规模的有如具有列表功能的小应用程序(如Applet), 而大的构件可以是浏览器这样的完整的应用系统。构件通过其接口向外界提供功能入口。接口是构件内一组功能的集合,它包含的是功能函数的入口,类似于C++中只有虚函数成员的纯虚类。外界通过接口引用或接口指针来调用构件内的功能函数。容器类似于装配车间,是一种存放相关构件的"器皿",用于安排构件、实现构件间的交互,其形式也是多种多样的,如表格(Form)、页面(Page)、框架(Frame)、外壳(Shell)等。另外,容器也可以作为另一个容器的构件。
推动构件技术发展的最大动力之一是软件重用。软件重用就是利用已有的软件成分来构造新的软件,它可以减少软件开发所需的费用和时间,且有利用提高软件的可维护性和可靠性。构件软件是目前发展最快的软件重用方式。构件软件解决两个重要问题: 一是重用,即构件具有通用的特性,所提供的功能能为多种系统使用; 二是互操作,即不同来源的构件能相互协调、通信,共同完成更复杂的功能。
构件软件技术是一种社会化的软件开发方法, 它使得开发者可将由不同语言、不同供应商开发的构件组合在一起来构造软件。构件软件和Internet一起被列为目前软件产业两个最重要的增长点, 受到了业界的高度重视。许多大公司都先后开发出了已被广泛使用的构件,如Microsoft的VBX、OCX及ActiveX控件,Borland公司的Delphi中数据访问构件等。软件构件的迅速发展使得基本构件装配应用开发模型成为一种深入到软业界的新的应用开发模式与开发环境。
在构件对象模型中,对象是一种功能单元,是一种构件。它既可指对象类又可指对象类的实例。但此处的对象类与OOP中的对象类又有很大的不同:它有自己唯一的标识号(如COM/DCOM中的CLSID)。对象常常以独立的DLL或EXE的形式存在,对象之间只能通过标准的接口调用来相互作用。
接口是对象中功能相关的一组函数的入口,它类似于C++中只有纯虚成员函数的抽象基类,它的指针或引用指向一接口函数表,该函数表包含着接口的功能函数的入口。如下图所示:
接口为构件对象模型提供对象间互操作能力。接口的定义也是面向对象或基于对象的,它具有继承能力、封装性及多态性等OO特性。
对象和接口都有自己唯一的标识。系统通过这两个标识来寻找、识别不同的对象及其接口。对象表示必须在系统中进行登记。接口调用由调用者在调用时显式地给出,而对象标识则在程序中常常有一个名字映射,调用者在调用对象的接口时给出该对象的名字,系统根据对象登记表索引找到该对象。
接口定义语言(
IDL)接口通常都具有自己的定义语言(
Interface Definition Language,简称IDL)。接口定义语言只是为了接口设计的方便而采用的,它可使设计者容易读懂彼此的接口设计。IDL编辑器编译IDL代码,生成相应编程语言的头文件及客户代理和服务器代理对象。对象及其接口的描述都在IDL头文件中描述。
全球性网络使线上的所有设备和软件成为全球共享的浩瀚的资源,计算机环境也从集中式发展到分布式环境,开放式系统的发展使用户能够透明地应用由不同厂商制造的不同机型不同平台所组成的异构型计算资源,因此,分布式处理和应用集成自然而然地成为人们的共同要求。
构件对象模式下的分布式处理是指借助计算机网络将分布在不同地点的构件(即对象)组织在一起,进行信息处理的一种方式。分布式处理中的构件可能由不同的厂商开发、生产,因而构件之间可能存在不一致的接口;另外,构件之间的通信也可能使用不同的协议,有延迟和失败的可能。国际上将这种兼容异质成分的分布式处理,称为开放分布式处理(ODP──Open Distributed Processing)。
概括地讲,开放分布式处理要达到以下几个方面的透明性:
(1)存取透明: 隐藏数据表示和调用机制的异同,使用同样的方式存取数据。
(2)失败透明: 将出错和恢复事件隐藏在对象内部,以达到容错的目的。
(3)位置透明: 隐藏接口的空间位置,用户不需关心接口是哪里提供的。
(4)迁移透明: 外界不需要知道系统为使资源均衡而改变对象的位置。
(5)持久性透明: 对象里隐藏着所用资源的变化,如处理器资源、存贮资源的冻结与解冻。
(6)重定位透明: 改变一个接口的位置不影响与之编联的其它接口。
(7)复制透明: 为提高性能,能同时有多个行为相同的对象支持某一接口, 而用户不需要知道有多个对象存在。
(8)提交透明: 一组对象发生作用的次序不影响结果的一致性。
挂靠于英国剑桥的APM公司在开放分布式研究方面独执牛耳。他们的"高级网络系统结构"(Advanced Networked Systems Architecture,简称ANSA 研究项目),受到世界上许多重要公司与研究机构的重视和资助,奠定了开放分布式处理的基础。这项研究独立于各种具体的网络、硬件、操作系统和数据库,着力于设计与构造灵活的分布式应用。其产品Aware是ANSA 体系结构的一个具体实现。
为了使开放分布式处理能达到处理异质构件的能力和上述八个方面的透明性, 国际标准化组织(ISO)制订了开放分布式处理的参考模型RM-ODP (Reference Model Of Open Distributed Processing),该模型的原型是挂靠在英国剑桥的APM公司的"高级网络系统结构"(Advanced Networked Systems Architecture, 简称ANSA。) 模型分成企业模型、信息处理模型、计算模型、工程模型和技术模型五类。这五类模型都与分布式系统的设计相关, 而其中的计算模型和工程模型与分布式系统体系结构的关系更为直接。计算模型主要研究客户/服务器结构及其对象所提供和享用的服务(Service)。 工程模型主要研究系统资源的分配以及如何用工程模型对象来支持计算模型对象。技术模型被用来实现工程模型对象到计算模型对象的映射, 它描述了如何利用各个本地操作系统中的进程映射和进程管理来具体实现上述映射。
1. 计算模型
计算模型的核心内容是服务。提供服务和接受服务的双方分别为服务器和客户端, 而对象(或构件)则是服务器和客户端的组成部分。一个对象可能是一个以上服务的提供者或使用者; 对象是经过封装、独立存在的, 一个对象可以被安装、升级、替换或重定位, 而与其它对象无关。
服务的提供与使用通过接口来体现, 即接口是提供服务的基本单元。
服务可分为两类, 即应用服务和体系结构服务。前者是系统所要完成的特定的任务; 后者是指各种任务都要涉及到的服务, 例如, 在一个分布式系统中登记或查询一种应用服务, 对使用权限进行控制以及其它的接口管理服务等。"交易(Trading)"是最典型的体系结构服务, 它通过系统拥有的目录结构来记录服务器对象所提供的服务; 另一方面,客户对象也通过"交易"来寻找所需的服务。提供这种"交易"服务的对象被称为"交易器(Trader)"。
对象的通信是通过传递接口引用(Interface Reference)进行的。接口引用对应用程序来说, 是一个网络指针, 指向提供服务的对象; 从面向对象的角度看, 接口引用就是接口实例的索引。接口引用可由一个程序自由地传给另一个程序,这也就把使用某种服务的能力传递给了对方。
一个对象可以在"交易器"中登记它所提供的服务, 也可以从"交易器"中查找所需要的服务, 所有的工程模型对象都清楚"交易器"对象的位置,并可以与之连结,这使得客户端与服务器的对象之间可以实现动态联编(Binding)。
除了登记和查询服务之外, "交易器"还提供了许多设施使管理员可以进行"交易器"内部的组织。例如,"交易器"提供了撤除接口引用、释放资源和关闭"交易器"的接口, 它可以给接口引用附加不同的空间位置属性和引用限定, 与接口引用名称一起提供给应用程序, 以便于接口的使用。"交易器"还可以优化服务, 即在某个服务对象繁忙的时侯,启动包含相同服务的其它对象来满足客户端的要求。另外,"交易器"还可以做为其它"交易器"上服务的代理,或与其它"交易器"通过桥接联合成"交易器"群,沟通各个应用领域。
一个计算模型对象可以有多个接口, 每个接口可称为一种接口类型。不同的接口类型提供的操作(或服务)可以相同,也可以不同。它们之间的兼容性可形成父子关系,利用这种关系可以优化服务。是否公布某个接口, 供外界使用完全由应用程序设计者来决定。
2. 工程模型
工程模型中的主要概念是"节点(Node)"、"核(Nucleus)"和"封壳(Capsule)"。
一个"节点"可以指一台计算机、一个操作系统进程或一台模拟机, 也可以是由分布式操作系统管理的计算机网络, 在不同的场合"节点"有不同的粒度。一个"节点"的资源由一个称为"核"的工程模型对象来管理, "核"把资源赋于工程模型对象, 使工程模型对象成为一个自治的操作单元(或单独的地址空间), 我们称之为"封壳"。因而,一个支持多进程的"节点",如Unix, 可以支持多个"封壳", 而MS-DOS只有一个"封壳"。
"核"带给"封壳"的能力包括:
(1)"封壳"是一个受保护的地址空间,其操作即使失败也不会影响到其它的"封壳"。
(2)允许在"封壳"内对并发活动进行控制。
(3)可与其它"封壳"进行通信。
(4)保留交互中的状态。
(5)构筑其它"封壳"的能力。
"核"所提供的资源包括任务(Task)、线程(Thread)、事件同步机制、套接字(Socket)、接头(Plug)、通道(Channel)、历程(Session)和接口引用等。
任务是"封壳"中由一串操作形成的独立的执行路程; 线程是虚拟的处理器, 它与任务编联并为任务提供所需的资源。支持多任务的"封壳"必定支持多线程。事件同步机制包括事件计数器(Event Counter)与顺序器(Sequencer), 用于对多个线程进行同步。套接字、通道、历程等用于进行"封壳"之间的通信。
一个工程模型对象是可以分布、激活、湮灭、转移的最小单元, 是编译了的计算模型对象。 由于可以把一个程序编译成一个单元, 也可以就单独的对象分别编译, 因此, 一个工程模型对象就是一个或多个运行时的计算模型对象。工程模型对象并不具备前面提到的透明性。透明性是在编译计算模型对象, 把透明服务加到附加操作与交互状态中而达到的。根据不同的需要可选择不同的透明性。
构件对象模型系统的典型结构
一构件对象模型系统的结构常可分为上、中、下三层,或可称之为基本程序结构、远程结构和线路协议(wire protocol)结构。如图所示:
客户代理(Client Proxy)和 对象代理(Object Proxy)是由接口语言定义的代码,它们分别居留在客户进程空间和服务器的进程空间,两着都是用来为接口参数的传递作准备工作。客户代理被用来按线路协议的要求将对一接口的调用参数打包(称为marshaling过程)或对调用结果解包(称为unmarshaling过程);对象代理则对接口的调用参数和调用结果分别实施unmarshaling过程和marshaling过程。运行库被用来支持客户与对象间的通信,并为这种通信提供空间透明性,包括本地进程间的透明和远程透明。线路协议层被用来运载接口调用参数和调用结果。
当客户发出对一对象的接口调用后,客户所在机器的运行库1负责寻找该对象所在的位置并将具体实施该调用。当该对象为远程对象时,运行库1通过线路协议层将调用参数传输到该对象所在机器的构件运行库2,通知运行库2实施本调用,运行库2将调用结果返回到运行库1,由运行库1将调用结果送给客户。在此过程中,如果远程对象处于非活动状态,则运行库2将之激活。
构件对象模型结构中的客户
/服务器模型在接口的调用过程中,调用者(应用程序或对象)充当客户的角色,而被调用的接口所属的对象则相当于服务器。
客户应用对接口的调用必须经与运行库的参与,运行库的作用即是三层客户服务器结构中的中间层所起的作用,因此如下图所示,客户应用──运行库──服务器组成了三层结构的客户/服务器模型。
构件对象模型的技术规范
目前构件与开放分布式系统模型理论已经在实际中得到了越来越广泛的应用。当前应用较多的有以下三种技术规范或体系结构:一曰
CORBA(Common Object Request Broker Architect)、二为COM/DCOM(Component Object Model / Distributed Component Object Model)、三称Java Beans。 除这三者之外,以下规范也可被用来构造分布式构件系统:CORBA是由OMG(Object Management Group)在1989年提出,得到了从IBM、Microsoft、Sun、HP、Oracle、 DEC到Iona、Visigenic、VPM等公司的广泛支持。COM/DCOM规范是Microsoft在独家发布的构件对象模式技术规范, 而Java Beans则是SUN公司在1994年12月提出的基于Java的构件模型。