西安电子科技大学电子教案 • 2008
《软件构件与中间件技术》
张立勇 宋胜利
zhang_liyong@163.com
shlsong@xidian.edu.cn
(西安电子科技大学软件学院,710071)
主要内容:
概述:中间件与软件构件的动因与基本概念。
CORBA 中间件:CORBA 的基本原理、CORBA 应用的基本开发过程(CORBA 构
件的开发与使用)、CORBA 中构件接口的编写、CORBA 服务端程序的编写。
Java 企业版中间件:J2EE 的基本概念、EJB 构件的开发与使用、Java 企业版中间
件服务的使用。
Web Service 体系结构:Web Service 体系结构简介、SOAP、WSDL、UDDI。
本书的关注点主要有两个:
如何开发与使用基于特定中间件的构件
如何使用中间件提供的各种支持
本书中所有例子程序均使用 Borland 公司的 VisiBroker for Java 4.5.1 和 Sun 公司的 Java
企业版参考实现平台开发,这些例子很容易移植到其他开发平台。读者可从西安电子科技大
学相关教学网站下载这些例子程序的全部源代码。
声明:本书 CORBA 部分(第二部分)内容来自于从网络途径获得的由李文军、周晓
聪、李师贤三位老师编写的中山大学学习资料《分布式软件体系结构》,其中少量地方根据
个人观点进行了修改。本书仅用于西安电子科技大学的教学用途。
- 1 -
西安电子科技大学电子教案 • 2008
第一部分 概述
第 1 章 软件构件与中间件基本概念
本章介绍分布式软件的基本概念、软件构件的基本概念、中间件的动因与基本概念;利
用 jdk 的远程方法调用 Java RMI 开发了一个简单的分布式应用程序,通过该例子演示软件
构件与中间件技术为软件开发提供的基本支持。
§ 1.1 分布式软件的基本概念
1.1.1 分布式软件与客户机/服务器模型
在计算机硬件技术与网络通信技术的支持下,应用需求驱使计算机软件的规模与复杂度
不断增长,软件正变得无处不在,同时软件所面临的挑战也正在日益加剧,软件开发过程中
复杂度高、开发周期长、可靠性保证难等问题日益突出。在这种背景下,软件开发人员不得
不在软件开发的过程中寻求更多的支持,以帮助其在特定的开发周期内开发出规模更大、更
可靠的软件系统。
本书关注在上述背景下大型分布式软件系统的开发支撑。原因主要有两个:
随着网络与通信技术的发展,分布式软件的应用越来越广泛,分布式软件在计算机
软件应用领域扮演着非常重要的角色。
分布式软件一般比集中式软件规模大、复杂,是软件开发复杂性的集中体现。
简单地讲,分布式软件指运行在网络环境中的软件系统,而网络环境是一群通过网络互
相连接的处理系统,每个处理节点由处理机硬件、操作系统及基本通信软件等组成。分布式
计算有两种典型的应用途径。第一种应用途径是将分布式软件系统看作直接反映了现实世界
中的分布性,例如当今许多业务处理流程通常呈现一种分布式运作方式,如某生产制造企业,
其负责加工制造的工厂可能位于珠江三角洲一带,而负责销售的部门则可能分别位于北京、
上海和广州,这时负责业务流程的软件系统显然也应做相应的分布式处理。第二种应用途径
主要用于改进某些应用程序的运行性能,使它们比单进程的集中式实现更具有效率,如利用
互联网上的大量计算机实现海量数据的科学计算或分析,此时软件系统的分布性并不是现实
世界中分布性的映射,而是为利用额外的计算资源而人为引入的。
分布式软件通常基于客户机/服务器(Client/Server)模型。如果一个系统两个组成部分
存在如下关系:其中一方提出对信息或服务的请求(称为客户机),而另一方提供这种信息
或服务(称为服务器),那么这种结构即可看作是一种客户机/服务器计算模型。互联网的
许多应用程序都采用客户机/服务器模型,例如 Web 浏览器与 Web 服务器、电子邮件客户
程序与服务程序、FTP 客户程序与服务程序等;更一般地,在普通的函数或对象方法调用中,
执行调用语句的子程序与实现函数/方法体的子程序或对象可看作一种客户机/服务器模
型,其中实现方是服务器,调用方是客户机。
分布式软件与传统的集中式软件主要区别在于强调客户端与服务端在地理位置上的分
离,这种分离可带来许多好处:
更好的支持平台无关性:客户端和服务端可以运行在不同的硬件(PC、工作站、
- 2 -
西安电子科技大学电子教案 • 2008
小型机等)与操作系统(Windows、Unix、Linux 等)平台上;
更好的可扩展性:可以在服务端功能不变的前提下对服务端的程序进行改进或扩
充,而这种改进或扩充不会影响到客户端的应用程序。
当然客户端与服务端的分离也使得软件系统更复杂:
开发人员不得不分别编写客户端和服务端应用程序,并力求保持两者的一致性;
软件系统的调试、部署、维护更加困难;
需考虑更多的可靠性、安全性、性能等软件质量因素。
1.1.2 分布式软件的三层/多层结构
早期的分布式系统基于图 1-1 所示的两层结构。在两层结构中,简单地将软件系统划分
为服务器层和客户层,服务器层又称为数据层。在服务器层,一般放置一个数据库服务器,
上面安装一个数据库管理系统,存放系统用到的持久数据。而客户层则实现系统的主要业务
功能,实现时需要访问数据库中存放的数据,一般会有多个客户端同时访问数据库服务。这
时的系统结构比较简单,就是多个客户端程序共享一个数据库。
数据库服务器
数据库
客户向服务器请求
数据库服务
服务器(数据)层
客户层
Client
Client
Client
存
储
过
程
业
务
逻
辑
代
码
数据库
用
户
界
面
代
码
图 1-1 两层结构的分布式系统
两层结构中软件开发的主要工作量在客户层。数据层基本没有什么程序代码,主要就是
建好数据库,可能利用存储过程实现一些基本的业务逻辑。开发人员所编写的代码几乎全部
都在客户端,一般可以把客户端的代码分为用户界面相关的代码和业务逻辑相关的代码,在
客户端的代码中要访问数据库中的数据,可以执行一些 SQL 语句或调用存储过程。
两层结构下,客户程序直接访问数据库,并且用户界面代码和业务逻辑代码交织在一起,
这些导致两层结构存在以下重要的缺陷:
第一,客户端的负担比较重。一般认为,客户端程序只要为使用该系统的用户提供一个
人机交互的接口就行了,但是在两层结构下,客户端仍然需要进行比较复杂的数据处理,因
为客户端从数据库中得到的仅仅是一些原始的数据,必须按照业务逻辑的要求对这些数据进
行一定的处理后才能呈现给用户,所以客户端的负担比较重。
第二,客户端的可移植性不好。处理复杂必然牵涉更多的移植性问题,另外在两层结构
下,每个客户端上都要安装数据库驱动程序,移植至少需要重新安装数据库驱动。
第三,系统的可维护性不好。因为客户端包含过多的业务逻辑,并且业务逻辑与人机交
互界面交织在一起,无论是用户界面需要修改,还是业务逻辑需要修改,都很麻烦。
- 3 -
西安电子科技大学电子教案 • 2008
第四,数据的安全性不好。两层结构下,数据库必须为每一个客户端机器开放直接操作
数据库的权限,这时就很难防止一个恶意的用户在某个客户端机器上利用该权限执行其不应
该执行的操作。
鉴于以上原因,人们提出了图 1-2 所示的三层结构:
数据库服务器
数据库
中间层服务器向数
据库服务器请求
中间层应用
程序
客户向中间层服务
器请求
服务器(数据)层
中间层
中间层
客户层
Client
Client
Client
图 1-2 三层结构的分布式系统
数据库
存
储
过
程
业务
逻辑
代码
用
户
界
面
代
码
在 3 层结构下,在数据层和客户层之间再增加一个中间层,将原来放在客户端的业务逻
辑代码移到中间层来。客户程序与数据库的连接被中间层屏蔽,客户程序只能通过中间层间
接地访问数据库,即降低了客户端的负担、改善了其可移植性,又提高了系统的数据安全性;
同时业务逻辑代码与用户界面代码相对独立,也在很大程度上提高了系统的可维护性,较好
地解决了两层结构的上述问题。
三层结构中软件开发的主要工作量在中间层,中间层包括除用户界面代码与持久数据之
外的几乎所有系统代码,是整个软件系统的核心。
在 3 层结构中,客户层和数据层已被严格定义,但中间层并未明确定义。中间层可以包
括所有与应用程序的界面和持久数据存储无关的处理。假定将中间层划分成许多服务程序是
符合逻辑的,那么将每一主要服务都视为独立的层,则 3 层结构就成为了 n 层结构。典型地,
可将业务逻辑层分离出实现数据持久化操作的持久层,用于实现对于持久数据操作的封装,
从而形成由客户层、业务逻辑层、持久层与数据层构成的四层结构。
- 4 -
西安电子科技大学电子教案 • 2008
§ 1.2 软件构件的基本概念
本节从分布式对象的角度讨论软件构件的特性。分布式对象是构成分布式系统的软件构
件,除了具备一般软件构件的特征外,其重要特征就是分布特性。
1.2.1 对象到构件的发展
按照面向对象的观点,软件系统由若干对象组装而成,将这一观点延伸至分布式系统,
分布式系统由若干分布式对象组装而成。面向对象的精髓之一在于对象维护自身的状态并通
过消息进行通信,这对于分布式计算环境是非常理想的,但是分布式对象与传统对象相比,
有其特殊的特性。
首先,分布式系统由于其规模与分布特性等原因,比集中式系统更容易被拆分给不同的
人或团队开发,这就很有可能遇到不同的人或团队习惯使用不同的程序设计语言和环境的情
况。但是,这些使用不同语言的人(团队)开发的程序要能够方便的交互,换句话说,就是
用不同的语言所写的对象要能够方便的交互。而在传统的集中式面向对象系统中,显然对象
之间的交互是局限于某种特定的语言的。从语言这个角度我们可以看到,分布式对象比传统
对象面临的环境更复杂,这要求分布式对象比传统对象具备更好的封装特性,比如,要把实
现所使用的语言屏蔽起来,对象的使用者看到的是一个跨语言的对象。
更进一步讲,分布式系统要求分布式对象可以在任何粒度上透明的使用,也就是说,无
需考虑位置与实现。不需要考虑具体在哪,是与使用者在同一个进程内,还是在不同的进程
内,如果不同又在哪个进程内,或是在哪个机器上的哪个进程内,或者是运行在什么样的操
作系统之上等等,这些具体的位置信息使用者都不希望去过多的关心。另外也不需要关心对
象的具体实现细节:如是用什么语言实现的,是不是用面向对象的语言实现的,还是用一个
函数库甚至是一个面向对象数据库实现的,都不用去关心。
传统的面向对象语言中的对象很难满足上面提到的要求。传统对象的关注点是封装和通
过继承对实现进行重用,封装提供了一种将对象实现细节与其他对象屏蔽开的严格方法,可
以大大缓解在面向过程系统中较突出的维护问题,继承提供了一种重用对象实现的简便方
法。而分布式系统要求分布式对象要有更好的可插入性,这个要求仅仅依靠传统面向对象的
封装和继承是不可能满足的。首先,要求另一层次上的封装,只需暴露公用接口;其次,从
重用的角度来讲,继承局限于程序设计语言,而分布式系统不太关注于直接重用代码,而是
要求能够利用远程所实现的服务。这就是说,分布式系统中的分布式对象和传统的对象不一
样,实际上是具有良好封装特性的软件构件。
一般地讲,构件指系统中可以明确辨识的构成成分,而软件构件指软件系统中具有一定
意义的、 相对独立的构成成分,是可以被重用的软件实体。构件提供了软件重用的基本支持,
分析传统工业,如机械、建筑等行业,以及计算机硬件产业,其成功的基本模式是符合标准
的零部件(构件)生产与基于标准零部件的产品生产(组装),其中复用是必需的手段,而
构件是核心和基础,这种模式是产业工程化、工业化的必由之路,也是软件产业发展的
必然途径,这是软件复用与软件构件技术受到高度重视的根本原因。
由于本书关注分布式系统,对应软件构件也关注分布式构件,因此除非特别声明,以后
论述中不区分构件与分布式对象这一对概念,一般提到的构件均指分布式构件,即分布式对
象,反之亦然。
1.2.2 软件构件的特性与相关概念
与对象相比,构件通常具有如下特性:
- 5 -
西安电子科技大学电子教案 • 2008
构件是一个严格定义的可插入单元:类似于硬件模块,一旦开发完成,就可以方便
的用来组装系统。构件一般是基于对象实现的,但也可以不作为对象实现。
构件将封装运用到了极限:构件通过封装来隐藏构件的实现以达到:
构件的实现语言是未知的:如一个 Java 客户端不会感觉到所使用的构件是
由 C++实现的。
构件的物理位置是未知的:一个 VB 客户端不会感觉到所使用的构件是运行
在相同的进程内(使用 DLL),还是在同一机器的不同进程内,甚至是位于
不同机器上。
构件通常在容器中进行管理:按照上面的讨论,构件要屏蔽实现语言、实现方式等
很多实现细节,使用一个构件时可以不关心具体实现和位置。这仅是指开发人员不
用关心,是不是谁都不用管这些事情,当然不是,如果谁都不去处理不同语言、不
同实现方式、不同的物理位置所带来的差异,那用不同语言、不同实现方式实现的、
位于不同的物理位置的构件就不可能很好的交互。那具体谁去作这个工作呢?通常
的做法是设置容器来为构件一个运行环境,容易是一种特殊的应用程序,构件在容
器中运行和管理。当有客户端要访问某个构件时,实际是向容器发起了一个请求,
容器再去判断构件的具体实现语言、实现方式以及构件的具体物理位置,然后帮助
请求者与构件进行交互。也就是说,我们所使用的、具备很好特性的构件实际上是
容器和我们用各种语言、方式所编写的程序共同协作的结果。这就要求构件遵循所
处的容器的规则,并按照标准的途径向容器发送事件。
构件可以从容器中获得属性或服务:如构件可以使用容器的背景色作为自己的背景
色。
构件允许对所支持的接口进行动态发现和调用:客户程序可以在运行状态下确定一
个构件支持何种功能,然后调用该功能。
既然构件具备极好的封装性和可插入性,那么基于构件的系统从可维护性上来讲就可以
达到一种比较理想的状态。如图 1-3 所示,一个构件化的软件系统在进行维护或升级时,在
保持构件接口不变的前提下,可单独对系统中若干个构件进行修改,而不会影响构成系统的
其它构件。
接口保持不变
软件系统版本1
软件系统版本2
构件1
构件3
构件5
构件2
构件4
构件6
构件1‘
构件3‘
构件5
构件2
构件4
构件6
图 1-3 构件化软件系统的升级方式
- 6 -
西安电子科技大学电子教案 • 2008
下面介绍几个构件相关的概念。
接口:接口是系统中用来定义分布式对象能力的约定。由于构件将封装运用到了极
限,构件之间相互看到的就只有接口。这里的接口和程序设计语言,如 Java 中的
interface 所起的作用基本一致,但构件的接口通常是跨语言的。
数据类型:分布式对象之间不可避免的要进行交互,而交互的最基本支撑就是要定
义在分布式对象之间传输的数据类型。一般说来,现有程序设计语言中已有的数据
类型不能直接在分布式系统中使用,因为分布式系统通常涉及多种程序设计语言与
多个平台,而不同语言或平台的数据类型往往不能兼容,如整型数在不同的语言或
平台上可能字节数或字节顺序不尽相同,因此一般需要一种独立于语言和平台的数
据类型系统。
编组与解组(Marshaling and Unmarshaling):分布式对象之间交互时,由于一般
至少跨越了进程边界,因此交换的数据通常要在网络上进行传输,而网上传输的数
据只能是串行化的流数据,所以需要把程序员熟悉的有类型的数据转化成便于网络
传输的流数据发送出去,并且需要把网络上接收到的流数据转化成程序员容易处理
的有类型数据,这就是编组与解组的过程。编组过程将数据封装成标准的格式以便
于传输,解组过程则负责打开传输来的数据。
对象句柄(Object Handle):对象句柄是在客户程序的编程语言或脚本环境内用来
引用分布式对象的实例。从功能角度上讲,对象句柄类似于面向对象语言中的对象
指针或对象引用,但是具体实现上和对象指针或对象引用却存在本质的差别,由于
对象句柄是对远端分布式对象的引用,因此不可能像对象指针或对象引用那样指向
对象在内存中的首地址。
对象创建(Object Creation):和面向对象语言中使用一个对象要先 new 类似,分
布式对象系统必须为创建一个新的分布式对象实例提供一种机制,但是这也不同于
简单的 new,要涉及更多的其它工作,分布式系统中经常使用工厂(factory)来完
成对象创建工作。工厂是一种特殊的分布式对象类型,常用来创建其它的分布式对
象。
对象调用(Object Invocation):分布式对象系统必须为分布式对象的调用提供一
种机制。通常情况下开发人员不希望自己写代码编组与解组这些复杂的底层工作,
而是希望像使用面向对象语言中的对象那样实现分布式对象的调用,通过后面的讨
论我们可以发现,有了中间件的支持就可以实现。但是分布式系统的开发人员一定
要随时牢记,分布式对象的调用一般会涉及一个多方参与的跨越网络通信的过程,
忽略这种区别会给开发的系统带来很大的危害。
§ 1.3 中间件的基本概念
1.3.1 中间件的动因
尽管有了构件技术的支持,但是随着软件系统规模与复杂度的不断提高,软件开发过程
中复杂度高、开发周期长、可靠性保证难等突出问题并没有得到根本缓解;而分布式软件面
临更大的挑战,分布式软件所运行的网络环境具有明显的分布性、开放性、演化性、异构性、
并发性等特征,因此分布式软件必须解决互操作、数据交换、分布性、可行性等一系列更复
杂的问题。
究其本质原因,在于人们控制复杂性的能力相对稳定,但面临的问题却越来越多。在现
- 7 -
西安电子科技大学电子教案 • 2008
实生活中,如果遇到一件很复杂的事情要完成,我们往往会寻求工具的支持,很多工具的作
用是帮人们完成重复性的、每次手工做起来又很费力费时的工作,在软件开发时解决问题的
思路是一致的。基本的解决思路就是抽取软件的共性成分,抽取的共性成分由系统级软件完
成,向开发人员屏蔽系统低层的复杂度,从而在高层保持整体复杂度的相对稳定。在软件领
域,这种解决思路往往导致新型系统软件的产生。操作系统与数据库管理系统的产生就是经
历了类似这样的过程。
在操作系统出现之前,计算机的初始组成就是“硬件+程序”,即程序直接运行在裸机
硬件之上。此时,应用程序直接控制硬件的各种运行细节,应用程序中存在大量的代码用于
管理各种物理器件,以访问数据为例,程序必须控制怎样连接磁盘,如何读取其中的数据,
如何处理各种异常情况等。这使得程序代码十分庞大,而且正确性难以保证。随着计算机应
用的日益广泛,程序的规模不断增大,软件开发变得越来越困难。在这种背景下,人们进行
了软件共性的第一次抽取,即抽取出了程序的共性(稳定)成分——计算机资源管理,此次
共性的抽取导致了操作系统的产生,分离出了应用程序。初期的操作系统被称为管理程序或
监督程序,提供大量的与硬件相关的代码(系统调用)来完成上层应用程序的各种请求,隐
藏了与硬件相关的程序执行过程的复杂性,从而简化了应用程序的开发。
操作系统形成之后,计算机的组成变成了“硬件+操作系统+应用程序”。此时,应用
程序中访问的数据和应用程序一样以简单文件的方式存储,应用程序的开发人员需要了解数
据的具体组织格式,并且需要自己编写程序解决完整性等相关问题。随着应用程序处理的数
据规模越来越大,应用程序中数据管理这一共性也越来越明显,即应用程序中普遍存在大量
代码实现数据管理功能。于是人们进行了软件共性的第二次抽取,即抽取出了程序的共性(稳
定)成分——数据管理,此次共性的抽取导致了数据库管理系统的产生,分离出了应用软件。
数据库管理系统对数据进行统一的管理和控制,并保证数据库的安全性和完整性,为用户屏
蔽系统关于数据存储和维护等的细节,从而再次简化了应用程序的开发。
类似的工作仍在继续,在软件系统规模与复杂度不断提高的同时,人们不断从应用软件
中提取共性、降低高层复杂性,最终导致了中间件的产生。与操作系统、数据库管理系统类
似,中间件是在操作系统(数据库管理系统)与应用系统之间的一层软件,通常为分布式应
用的开发、部署、运行与管理提供支持。
1.3.2 中间件提供的支撑
在中间件应用的早期,人们依据所抽取出的应用软件中的不同共性设计与实现了多种类
型的中间件,一般一种类型的中间件实现一种共性功能,为应用软件提供一种开发支撑。由
于所属的具体领域不同,面临的问题差异很大,因此不同开发组织分离、开发出的中间件也
不尽相同。以下是几种常见的中间件以及其提供的支持:
终端仿真/屏幕转换中间件:用以实现客户端图形用户接口与已有的字符接口方式的服
务器应用程序的互操作。在该种中间件支持下,可以很容易地为原有字符界面的应用程序提
供图形用户界面。
数据访问中间件:在数据库管理系统的基础上,对异构环境下的数据库实现联接或文件
系统实现联接的中间件,为应用程序访问数据库提供开发支撑。
远程过程/方法调用中间件:用以实现远程过程或方法调用的中间件。向应用程序提供
远程调用时的底层通信支持,帮助应用程序完成编组与解组等工作,程序员方便地编写客户
端应用程序,像调用本地过程或对象那样方便调用位于远端服务器上的过程或对象方法。
消息中间件:为应用程序提供发送和接收异步消息支持的中间件。基于消息的交互方式
提供了基本的异步编程模式,即客户端可以通过发送消息来请求某种服务,在服务端处理请
求期间,客户端不必等待对方完成,可以执行其它操作,服务端完成后会以消息的形式通知
- 8 -