Java RMI进阶之原理篇 - 高飞网
122 人阅读

Java RMI进阶之原理篇

2017-07-28 02:09:46

一、RMI概览

    Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能简化远程接口对象的使用。

    Java RMI极大地依赖于接口。在需要创建一个远程对象的时候,程序员通过传递一个接口来隐藏底层的实现细节。客户端得到的远程对象句柄正好与本地的根代码连接,由后者负责透过网络通信。这样一来,程序员只需关心如何通过自己的接口句柄发送消息。

    接口的两种常见实现方式是:最初使用JRMP(Java Remote Message Protocol,Java远程消息交换协议)实现;此外还可以用与CORBA兼容的方法实现。RMI一般指的是编程接口,也有时候同时包括JRMP和API(应用程序编程接口),而RMI-IIOP则一般指RMI接口接管绝大部分的功能,以支持CORBA的实现。

    最初的RMI API设计为通用地支持不同形式的接口实现。后来,CORBA增加了传值(pass by value)功能,以实现RMI接口。然而RMI-IIOP和JRMP实现的接口并不完全一致。

    RMI应用通常会包含两部分程序,一个服务端,一个客户端。典型的服务端程序会创建一些远程对象,提供这些对象的引用用以访问,最后等待客户端调用这些远程对象的方法。而一个典型的客户端程序,会去服务端获取远程对象的引用然后调用对象上的方法。RMI提供了服务端与客户端通讯的机制,来回传递消息。这样的一种应用有时称为“分布式对象应用(distributed object application

    分布式对象应用需要做到:

  1. 定位远程对象。应用可以使用多种机制来获取远程对象的引用。例如,应用可以将远程对象使用一个简易的名称注册到RMI的注册表。或者通过其他远程调用返回一个远程对象的引用。
  2. 与远程对象的通讯。与远程对象间的通讯细节是通过RMI来处理的。对开发者来说,远程通讯和Java本地的调用几乎没有区别。
  3. 可以远程加载类定义。由于RMI可以将对象进行传递,它提供了远程传递对象数据来加载对象类定义的机制。


    下图描述了RMI分布式应用使用RMI注册表来获取远程对象引用的细节。服务端调用注册表来关联(或者说绑定)一个远程对象到一个名字上。客户端就可以通过名字来从服务端的注册表来查找远程对象了,既而就可以调用对象上的方法。该插图同时也展示了RMI系统使用一个现存的web服务加来加载类定义,从服务端到客户端、从客户端到服务端。

    


二、RMI的三层模型

1.客户端

        1)存根(StubObject):远程对象在客户端上的代理;
        2)远程引用层(RemoteReference Layer):解析并执行远程引用协议;
        3)传输层(Transport):发送调用、传递远程方法参数、接收远程方法执行结果。

2.服务端

        1)骨架(Skeleton):读取客户端传递的方法参数,调用服务器方的实际对象方法,并接收方法执行后的返回值;
        2)远程引用层(Remote ReferenceLayer):处理远程引用语法之后向骨架发送远程方法调用;
        3)传输层(Transport):监听客户端的入站连接,接收并转发调用到远程引用层。

3.注册表(Registry)

以URL形式注册远程对象,并向客户端回复对远程对象的引用。

又从技术的角度上讲,有如下几个主要类或接口扮演着上述三层模型中的关键角色:
    1)注册表:java.rmi.Naming和ava.rmi.Registry;
    2)骨架:java.rmi.remote.Skeleton        
    3)存根:java.rmi.server.RemoteStub
    4)远程引用层:java.rmi.server.RemoteRef和sun.rmi.transport.Endpoint;
    5)传输层:sun.rmi.transport.Transport


三、工作过程

在实际的应用中,客户端并没有真正的和服务端直接对话来进行远程调用,而是通过本地JVM环境下的存根对象来进行的。

1.远程调用过程

    1)客户端从远程服务器的注册表中查询并获取远程对象引用。当进行远程调用时,客户端首先会与存根对象(Stub Object)进行对话,而这个存根对象将远程方法所需的参数进行序列化后,传递给它下层的远程引用层(RRL);
    2)存根对象与远程对象具有相同的接口和方法列表,当客户端调用远程对象时,实际上是由相应的存根对象代理完成的。远程引用层在将存根的本地引用转换为服务器上对象的远程引用后,再将调用传递给传输层(Transport),由传输层通过TCP协议发送调用;
    3)在服务器端,传输层监听入站连接,它一旦接收到客户端远程调用后,就将这个引用转发给其上层的远程引用层;
    4)服务器端的远程引用层将客户端发送的远程应用转换为本地虚拟机的引用后,再将请求传递给骨架(Skeleton);
    5)骨架读取参数,又将请求传递给服务器,最后由服务器进行实际的方法调用。

2.结果返回过程

    1)如果远程方法调用后有返回值,则服务器将这些结果又沿着“骨架->远程引用层->传输层”向下传递;
    2)客户端的传输层接收到返回值后,又沿着“传输层->远程引用层->存根”向上传递,然后由存根来反序列化这些返回值,并将最终的结果传递给客户端程序。

    作为一般的RMI应用,JAVA为我们隐藏了其中的处理细节,而让开发者有更多的精力和时间花在实际的应用中

四、RMI的优缺点

1. 优点

    面向对象:RMI可将完整的对象作为参数和返回值进行传递,而不仅仅是预定义的数据类型。也就是说,您可以将类似Java哈希表这样的复杂类型作为一个参数进行传递。而在目前的RPC系统中,您只能依靠客户机将此类对象分解成基本数据类型,然后传递这些数据类型,最后在服务器端重新创建哈希表。RMI则不需额外的客户程序代码(将对象分解成基本数据类型),直接跨网传递对象。 

    可移动属性:RMI可将属性(类实现程序)从客户机移动到服务器,或者从服务器移到客户机。这样就能具备最大的灵活性,因为政策改变时只需要您编写一个新的Java类,并将其在服务器主机上安装一次即可。 

    设计方式:对象传递功能使您可以在分布式计算中充分利用面向对象技术的强大功能,如二层和三层结构系统。如果您能够传递属性,那么您就可以在您的解决方案中使用面向对象的设计方式。所有面向对象的设计方式无不依靠不同的属性来发挥功能,如果不能传递完整的对象--包括实现和类型--就会失去设计方式上所提供的优点。 

    安  全:RMI使用Java内置的安全机制保证下载执行程序时用户系统的安全。RMI使用专门为保护系统免遭恶意小应用程序侵害而设计的安全管理程序,可保护您的系统和网络免遭潜在的恶意下载程序的破坏。在情况严重时,服务器可拒绝下载任何执行程序。 

    便于编写和使用:RMI使得Java远程服务程序和访问这些服务程序的Java客户程序的编写工作变得轻松、简单。远程接口实际上就是Java接口。服务程序大约用三行指令宣布本身是服务程序,其它方面则与任何其它Java对象类似。这种简单方法便于快速编写完整的分布式对象系统的服务程序,并快速地制做软件的原型和早期版本,以便于进行测试和评估。因为RMI程序编写简单,所以维护也简单。 

    可连接现有/原有的系统:RMI可通过Java的本机方法接口JNI与现有系统进行进行交互。利用RMI和JNI,您就能用Java语言编写客户端程序,还能使用现有的服务器端程序。在使用RMI/JNI与现有服务器连接时,您可以有选择地用Java重新编写服务程序的任何部分,并使新的程序充分发挥Java的功能。类似地,RMI可利用JDBC、在不修改使用数据库的现有非Java源代码的前提下与现有关系数据库进行交互。 

    编写一次,到处运行:RMI是Java“编写一次,到处运行 ”方法的一部分。任何基于RMI的系统均可100%地移植到任何Java虚拟机上,RMI/JDBC系统也不例外。如果使用RMI/JNI与现有系统进行交互工作,则采用JNI编写的代码可与任何Java虚拟机进行编译、运行。 

    分布式垃圾收集:RMI采用其分布式垃圾收集功能收集不再被网络中任何客户程序所引用的远程服务对象。与Java 虚拟机内部的垃圾收集类似,分布式垃圾收集功能允许用户根据自己的需要定义服务器对象,并且明确这些对象在不再被客户机引用时会被删除。 

    并行计算:RMI采用多线程处理方法,可使您的服务器利用这些Java线程更好地并行处理客户端的请求。Java分布式计算解决方案:RMI从JDK 1.1开始就是Java平台的核心部分,因此,它存在于任何一台1.1 Java虚拟机中。所有RMI系统均采用相同的公开协议,所以,所有Java 系统均可直接相互对话,而不必事先对协议进行转换。

从最基本的角度看,RMI是Java的远程过程调用(RPC)机制。与传统的RPC系统相比,RMI具有若干优点,因为它是Java面向对象方法的一部分。传统的RPC系统采用中性语言,所以是最普通的系统--它们不能提供所有可能的目标平台所具有的功能。 

RMI以Java为核心,可与采用本机方法与现有系统相连接。这就是说,RMI可采用自然、直接和功能全面的方式为您提供分布式计算技术,而这种技术可帮助您以不断递增和无缝的方式为整个系统添加Java功能。

2. RMI缺点

    RMI只能调用由Java编写的远程服务,因此它不是跨语言的。


五、补充

Stub和Skeleton在哪里产生

    从JDK5.0以后,这两个类就不需要rmic来产生了 ,而是有JVM自动处理,实际上他们还是存在的。Stub存在于客户端,作为客户端的代理,让我们总是认为客户端产生了stub,接口没有作用。实际上stub类是通过Java动态类下载 机制下载的(具体内容请参考:Java RMI实现代码动态下载),它是由服 务端产生,然后根据需要动态的加载到客户端,如果下次再运行这个客户端该存根类存在于classpath中,它就不需要再下载了,而是直接加载。(具体的内部细节,需要参考Sun 的Rmi - Java Remote Method Invocation – Specification)。总的来说,stub是在服务端产生的,如果服务端的stub内容改变,那么客户端的也是需要同步更新。

rmiregistry介绍

    用一个图示来说明rmiregistry的作用:


    rmiregistry需要在提供远程对象服务端启动,它提供了一个环境,说白了就是在内存中,开辟了一片空间,用来接受服务端服务程序的 注册,产生一个类似于数据库,提供存储检索远程对象功能的注册表。这个RMI注册表,就是我们常听到的RMI名字服务。远程客户端,就是依靠它获得存根,调用远程方法。说到 这里有一个端口的问题,如果你在启动rmiregistry时,设定了非默认端口,那么需要在服务端和客户端统一使用该端口,否则就会有RemoteException的异常抛出,rmiregistry提 供的服务是针对特定的端口号的,不然在同一台机器上也是无法提供服务。

关于端口

在使用 RMI 发布服务时,会使用到两个端口。

一个是 RegisterPort,这个是 RMI 的服务注册端口,通过以下 API 来指定。而且服务注册端口必须要指定,默认使用 1099 端口。

Registry reg = LocateRegistry.getRegistry(registryPort);

注册端口是客户端服务连接的端口。

一个是 ServicePort,这个是 RMI 的服务的数据传输端口。该端口是真正在 RMI 客户端与服务端进行数据通信交互的端口。是由注册端口发现有客户端连接后,进行后续分配的端口。默认值为 0 表示使用匿名随机端口。

API 的指定方式如下:

UnicastRemoteObject.exportObject(this.exportedObject, this.servicePort);


RMI与CORBA的关系

    RMI 和 CORBA 常被视为相互竞争的技术,因为两者都提供对远程分布式对象的透明访问。但这两种技术实际上是相互补充的,一者的长处正好可以弥补另一者的短处。RMI 和 CORBA 的结合产生了 RMI-IIOP,RMI-IIOP 是企业服务器端 Java 开发的基础。1997 年,IBM 和 Sun Microsystems启动了一项旨在促进 Java 作为企业开发技术的发展的合作计划。两家公司特别着力于如何将 Java 用作服务器端语言,生成可以结合进现有体系结构的企业级代码。所需要的就是一种远程传输技术,它兼有 Java 的 RMI(Remote Method Invocation,远程方法调用)较少的资源占用量和更成熟的 CORBA(Common Object Request Broker Architecture,公共对象请求代理体系结构)技术的健壮性。出于这一需要,RMI-IIOP问世了,它帮助将 Java 语言推向了目前服务器端企业开发的主流语言的领先地位。 


参考:

Java远程方法调用

An Overview of RMI Applications (The Java™ Tutorials >

RMI 相关知识

RMI(Remote Method Invocation)原理浅析 - 博采众生 - 博客频道 - CSDN.NET

远程方法调用(RMI)原理与示例 - Pickle - 博客园

JAVA RMI分布式原理和应用 - - ITeye技术网站





还没有评论!
23.20.166.68