分布式系统要求分布于不同地址空间、不同宿主机上的计算之间能够相互通信。虽然语
言提供了一个基本的通信机制,即使用Sockets对一般的通信是足够的,且灵活的,但是Socke
ts要求客户和服务器在对交换的信息进行编码和译码时,要遵循应用级的协议,而这种协议设
计起来很麻烦,且易产生错误。
可以代替Sockets的机制是RPC(Remote Procedure Call),它把通信接口(界面)抽象
到过程调用一级。这样,程序员不用直接使用Sockets工作,他好象在调用一个本机过程,而实
际上,该调用的参数被打包,并传送到远程目标。RPC系统使用外部数据表示(像XDR),对参数
和返回值进行编码。
然而,RPC并不适用在需要不同地址空间上的程序级对象之间进行通信的分布式对象系统
。为了与对象调用的语义匹配,分布式对象系统需要远程方法调用或RMI。在这种系统中,本
机桩(Surrogate)对象管理对远程对象的调用。
一、Java分布式对象模型
1.基本术语
在Java分布式对象模型中,远程对象(Remote object)是指其方法可以在别的Java虚拟机
上(可能位于不同的宿主机上)调用的对象。
远程对象是由一个或多个远程接口(Remote interfaces)加以描述的。
远程接口是声明远程对象的方法的Java接口。
RMI是指远程对象的远程接口中方法调用的动作。
对远程对象的方法调用与本机对象的方法调用有相同的语法。
2.分布式对象模型与非分布式对象模型的比较
(1) 相同点
·在任何方法调用(本机的或远程的)中,都可以把远程对象的引用作为变元或返回结果
。
·使用Java中固有的映射语法,可以把一个远程对象映射为由实现支持的一组远程接口
中任意一个。
·可以使用Java的Instanceof操作符来测试远程接口是否由某个远程对象所支持。
(2)不同点
·远程对象的客户与远程接口交互,但从来不与实现这些接口的类交互。
·远程方法调用中的非远程参数和非远程结果是以拷贝方式传递的,而不是用引用(Ref
erence)方式传递的。这是因为对象引用只在单一的JVM中是有用的。
·远程对象通过引用传递,而不是拷贝真正的远程实现。
·Object类中定义的一些方法对远程对象有特殊的语义。
·由于远程对象调用的失败模式比本机对象调用的失败模式复杂,因此,客户必须处理在
远程方法调用中发生的其它异常。
3.远程对象与本机桩的类型等价
在分布式对象模型中,客户与本机桩(Surrogate)对象进行交互。桩对象的远程接口集与
远程对象的类所定义的远程接口集完全相同,桩类不包括组成对象的类型图的类层次结构中
的非远程部分,这是因为桩类是从实现一个或多个远程接口的最简化的实现类中产生的。例
如,如果C扩展了B,B扩展了A,但是只有B实现了一个远程接口,那么桩由B而不是由C产生出来
的。
由于桩与远程对象的类实现的是同一远程接口集,因此,从Java系统的观点来看,桩与服
务器对象的类型图中的远程部分有相同的类型。客户可以使用内在(固有)的Java操作,检查
远程对象的类型,从一个远程接口映射到另一个远程接口。
使用Rmic 编译器产生桩。
4.RMI中的参数传递
远程方法调用的变元或返回值,可以是能串行化的(Serializable)任意的Java类型,它包
括Java初等类型、远程Java对象和实现java.io.Serializable接口的非远程Java对象。对小
应用程序来说,如果本机不提供作为参数或返回值的类,那么它将借助于AppletClassLoader
动态地装入。对应用程序来说,这些类由装入应用程序的类装载器装入。这种类装载器可能
是缺省的类装载器(使用本机类路径),也可能是RMI类装载器(使用服务器的Codebase)。
某些类不能以非串行化方式传递,例如,由于安全的原因。当远程方法调用失败时,会引
发一个异常。
(1)传递非远程对象 作为远程方法调用的参数或结果传递的非远程对象,采用拷贝方式
传递。
也就是说,当远程方法调用中出现非远程对象时,在激发对远程对象的调用之前,首先拷
贝非远程对象的内容。缺省情况下,只拷贝非静态的和非临时域。
与此类似,当一个远程方法调用返回一个非远程对象时,在进行调用的虚拟机中首先创建
一个新对象
(2)传递远程对象 当把远程对象作为参数传递时,将传递远程对象的桩,作为参数传递的
远程对象只能实现远程接口。
5.RMI中的异常处理
由于远程方法在其特征(Signature)中包括java.rmi.RemoteException,因此,调用者必
须有处理这种异常的准备。当在远程方法调用中引发java.rmi.RemoteException异常时,客
户可能知道一点或根本不知道调用的结果,不知道失败是发生在调用结束之前,还是发生在调
用过程当中,或者是发生在调用结束之后。因此,远程接口及其说明的调用方法,在设计时应
考虑到发生故障时的语义。
二、系统体系结构
RMI系统包括三层:桩/骨架(Tub/Skeleton)层、远程引用(Remote reference)层和传输
(Transport)层。每一层的边界由确定的接口和协议加以定义。每一层都独立于其下一层,并
且可以在不影响系统中其它层的情况下,可用可选的实现替代。例如,目前传输层的实现是基
于TCP的(使用Java sockets),但是,我们可以用基于UDP的传输层来替代它。这是为Java语言
专门设计的。
另一门技术是动态桩装载(Dynamic stub loading),用于支持客户端桩。客户端桩与远
程对象本身实现的是同一组远程接口。当类型完全一样类型的桩不再为客户使用时,使用这
个技术,可允许客户使用Java中内建的强制转换操作符进行类型检查。
1.概述
RMI系统三层结构包括:
·桩/骨架层:客户端桩(代理)和服务器端骨架。
·远程引用层: 远程引用行为(像单个对象或复制对象的调用)。
·传输层:现成连接的设置和管理,以及远程对象的跟踪。
·应用层在RMI系统之上, 下层给出了各层之间的关系:
@@22103000.GIF;图1 RMI系统中各层之间的关系@@
从客户到远程服务对象的远程方法调用,沿RMI系统的各层从上到下,一直到客户端传输
层,然后再由下到上,从服务端传输层到服务器。
对远程服务对象的方法进行调用的客户,实际上是使用远程对象的桩或代理作为访问远
程对象的渠道。客户所拥有的远程对象的引用是一个本机桩的引用。这个桩是远程对象的远
程接口的实现,它借助于远程引用层把调用请求传送给服务对象。
远程引用层负责分析调用的语义。例如,决定服务器是一个单元素对象,还是一个需要与
多个位置通信的复制对象。每一个远程对象实现选择它自己的远程引用语义——服务者或一
个单元素对象,或者一个需要与它的复制对象进行通信的复制对象。
服务对象的引用语义也由远程引用层处理。例如,远程引用层概括出引用在以下服务器
中实现的对象的不同方式:一是总是在某台机器上运行的服务者;二是只有当对其进行某个方
法调用时才运行的服务者。在远程引用层以上的各层中,这些区别是看不出来的。
传输层负责连接设置、连接管理以及位于传输地址空间上的远程对象(远程调用的目标
)的跟踪和调度。
为了调度远程对象,传输层把远程调用传送到远程引用层。远程引用层处理任意服务端
的行为,这些行为需要在处理(Handing off)对服务端骨架的请求之前发生。远程对象的骨架
把调用传给远程对象实现,后者执行真正的方法调用。
调用的返回值以如下过程返回:从服务端的骨架层传到远程引用层,再传到传输层,然后
返回到客户端的传输层和远程引用层,最后到达客户端的桩层。
2.桩/骨架层
这一层是应用层与RMI系统其它部分之间的接口。这一层不处理任何传输的细节,它借助
于编组流把数据发送给远程引用层。编组流采用的是一种被称为对象串行化的机制,使Java
对象可以在地址空间之间被传送。使用对象串行化系统传送对象时,如果是远程对象,则通过
引用传送;否则,通过把对象拷贝到远程地址空间的方法传送。
远程对象的桩就是远程对象的客户端代理,它实现了远程对象实现所支持的所有接口。
客户端桩负责:
·远程对象的调用初始化(通过调用远程引用层)。
·对参数进行编组,形成一个编组流(从远程引用层获得)。
·通知远程引用层,应该激活调用。
·把来自卖座率的返回值或异常解编组。
·通知远程层,调用结束。
远程对象的骨架就是服务端的实体,它包括把调用分配给真正的远程对象实现的方法。
骨架负责:
·把来自编组流的参数解编组。
·向上调用真正的远程对象实现。
·对调用的返回值或异常编组,形成编组流。
桩和骨架是用Rmic编译器产生的。
3.远程引用层
远程引用层处理较低层的传输接口,也负责执行具体的远程引用协议,这个协议独立于客
户桩和服务端骨架。
根据情况每个远程对象实现选择自己的远程引用子类。在远程引用层,可以执行各种不
同的调用协议,如:
·单映射点到点调用。
·对复制对象组的调用。
·支持一种特定的复制策略。
·支持远程对象的持久引用(使远程对象的激活成为可能)。
·重新连接策略(远程对象不可访问)。
远程引用层有两个协同操作的部分,即客户端部分和服务端部分。客户端部分不能对远
程服务者(如果远程引用是关于复制对象的,则有多个远程服务者)提供特定的信息,它借助于
与服务端部分的信息传输而通信。在每个方法调用中,客户端部分和服务端部分执行具体的
远程引用语义分析。例如,如果远程对象是复制对象的一部分,那么客户端部分将把方法调用
传送给每一个该对象的复制对象,而不是只传送给某个单一的远程对象。
与客户端部分类似,服务端部分在把远程方法调用传送到骨架之前,先进行具体的远程引
用语义分析。例如,通过与复制组中其它服务者的通信,将保证原子的多映射传输。
远程引用层借助于面向流的抽象的连接把数据传送到传输层,传输层负责连接的实现细
节。虽然连接提供了一个基于流的接口,但是在这个抽象连接下,可以实现无连接的传输。
4.传输层
一般来说,RMI系统的传输层负责:
·设置与远程地址空间的连接。
·管理连接。
·监视连接的"活跃度"。
·监听呼入调用。
·维护存在于地址空间上的远程对象表。
·为呼入调用设置连接。
·为远程调用的目标寻找分配器,并把连接传递给它。
远程对象引用的表示包括一个终点(Endpoint)和一个对象标识符,这种表示被称为活引
用(Live reference)。假入给定一个远程对象的活引用,那么传输层将根据其终点来设置与
远程对象所在的地址空间之间的连接。在服务端,传输层将使用对象标识符来寻找远程调用
的目标。
RMI系统的传输层包括4个基本的抽象概念:
(1)终点(Endpoint)用于标识一个地址空间和Java虚拟机的一个抽象概念。在实现中
,终点可以被映射到传输,也就是说,给定一个终点,我们就可以获得一个具体的传输实例
。
(2)渠道(Channel)用于标识两个地址空间之间通道的抽象概念,它负责管理本机地址
空间与远程地址空间之间的连接。
(3)连接(Connection)表示转移数据的一个抽象概念(执行输入/输出)。
(4)传输(Transport)是用于管理渠道的抽象概念。渠道是地址空间之间的真正连接。在
一个传输中,在每一对地址空间(本机地址空间和远程地址空间)之间只存在一个渠道。给定
了表示远程地址空间的终点,传输就会设置与该地址空间之间的渠道。传输也负责接受对地
址空间的呼入连接的调用,为调用设置一个连接对象,并分配给系统中较高的层。
由于传输定义了终点的离散表示,因此可以存在多个传输实现。这种设计和实现也支持
每个地址空间的多个传输,在同一个虚拟机上可以同时支持TCP和UDP。注意,RMI传输接口只
对虚拟机实现是可用的,而对应用不是直接可用的。
5.远程对象的垃圾收集
与本机系统一样,有必要在分布式系统中自动地删除那些不再被任何客户使用的远程对
象。这样,程序员就不需要跟踪远程对象客户,而使远程对象能适当地终止。RMI系统使用一
种类似于Modula-3的网络对象引用计数垃圾收集算法。
为了完成引用计数垃圾收集,RMI运行系统跟踪每个Java虚拟机中的所有活引用。当一个
活引用进入Java虚拟机时,它的引用计数就加1。对象的第一个引用给对象的服务者发送一个
"已引用"信息。当在本机虚拟机中,活引用已不再被引用时,把引用计数减1。当对对象的最
后一个引用也已废弃时,就给服务者发送一个不再引用信息。由于协议中存在许多细微的差
别,大部分差别与引用信息和非引用信息的顺序的维护有关,因此为了保证对象不会过早地被
当作垃圾收集掉,应该密切关注引用信息和非引用信息的维护。
6.动态类装载
在RPC系统中,客户端桩代码必须在进行RPC之前产生,并与客户连接。客户端桩代码可以
静态地与客户连接,也可以借助与本机或在网络文件系统中可用的库的动态连接,在运行时与
客户连接。无论是静态连接还是动态连接,对客户机来说,处理RPC的以编译形式出现的具体
的代码必须是可用的。
RMI泛化了这种技术,它使用一种被称为动态类装载的机制,在运行时装载处理远程对象
的方法调用的类,这些类包括:
·远程对象类和它们的接口类。
·作为远程对象代理的桩类和骨架类。
·在基于RMI的应用中直接使用的其它类,如作为RMI参数或返回值的类。
三、RMI相关产品
利用Java的RMI技术,开发相关应用软件已成为一些公司的一个发展目标。现举以下几个
事例说明:
(1) Avitek公司使用RMI技术开发应用软件。这是一个基于健壮且可扩展的标准的应用
软件,在使用Windows 95或NT的Intranet中可以很容易地更新、修改和扩展。这个项目的第
一阶段已在1997年1月份顺利地完成,第二阶段目前正处于开发之中,预计1997年6月份完成。
(2) Dynamicobjects公司的perspectives。这是第一个集成化的文档管理器,与Javaso
ft的JDK 1.1、RMI和完整的JavaBeans模型完全一致。一组小而快速的构件为工作组的合作
和文档管理提供了一个以分布式文档为中心的、模块化的、可扩展的、并且独立于平台的环
境。
(3) IBM的San Francisco 计划。该计划重新确立了中小型企业和独立的软件开发者对
更为快速的应用软件开发的迫切需求。该计划以Java的RMI作为分布式设施的基础。之所以
选择RMI,是因为它与这个计划的分布式需求非常接近。
(4) Redcape 软件公司已开发了一个分布式策略框架,它使用RMI作为同一宿主机或不同
宿主机上的JVM之间通信的一种主要办法。 |