聊聊RMI
今天我想看看Java RMI开发,可能有些大佬会这样想:小菜鸡,现在谁还学这个,Spring Cloud、Dubbo不香吗?是的,从赚钱的角度看,掌握这些主流的框架很有竞争力。但我有一个毛病,如果不能把相对底层的逻辑捋顺清楚,很难有继续进行的动力,甚至会直接自我放弃,破罐子破摔。同时我还有个不好的习惯,那就是脑子笨记不住一切重要的东西,可能这就是我一直无法进步的原因吧。今天我想以RMI作为起点,用新的方式来帮助自己记住一些重要的知识。那就开始吧!
RMI基本概念及其特点
RMI,英文全称为:Remote Method Invocation,即远程方法调用。它是一种机制,能够让在某个Java虚拟机上的对象调用另一个Java虚拟机中的对象上的方法。关于RMI有以下几点需要了解:
- 它是Java的一组拥护开发分布式应用程序的API。RMI使用Java语言接口定义了远程对象,它集合了Java序列化和Java远程方法协议(Java Remote Method Protocol)。简单地说,这样使原先的程序在同一操作系统的方法调用,变成了不同操作系统之间程序的方法调用,由于J2EE是分布式程序平台,它以RMI机制实现程序组件在不同操作系统之间的通信。比如,一个EJB可以通过RMI调用Web上另一台机器上的EJB远程方法。
- Java在JDK1.1中引入了RMI(Remote Method Invocation,远程方法调用),它大大增强了Java开发分布式应用的能力。Java作为一种风靡一时的网络开发语言,其巨大的威力就体现在它强大的开发分布式网络应用的能力上,而RMI就是开发百分之百纯Java的网络分布式应用系统的核心解决方案之一。其实它可以被看作是RPC的Java版本。但是传统RPC并不能很好地应用于分布式对象系统。而Java RMI则支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用。
- RMI目前使用Java远程消息交换协议JRMP(Java Remote Messaging Protocol)进行通信。JRMP是专为Java的远程对象制定的协议。因此,Java RMI具有Java的“Write Once,Run Anywhere”的优点,是分布式应用系统的百分之百纯Java解决方案。用Java RMI开发的应用系统可以部署在任何支持JRE(Java Run Environment Java,运行环境)的平台上。但由于JRMP是专为Java对象制定的,因此,RMI对于用非Java语言开发的应用系统的支持不足。不能与用非Java语言书写的对象进行通信。
通过以上基本概念的讲解,我们知道Java Remote Method Invocation(RMI – Java远程方法调用)允许我们使用Java编写分布式对象。下面我们看看RMI的优点以及如何将其连接到现有和原有系统中,以及与用Java编写的组件的连接。首先RMI的优点有:
- RMI为采用Java对象的分布式计算提供了简单而直接的途径。这些对象可以是新的Java对象,也可以是围绕现有API的简单的Java包装程序。Java体现了“编写一次就能在任何地方运行的模式。而RMI可将Java模式进行扩展,使之可在任何地方运行”。
- 因为RMI是以Java为核心的,所以,它将Java的安全性和可移植性等强大功能带给了分布式计算。您可将代理和业务逻辑等属性移动到网络中最合适的地方。如果您要扩展Java在系统中的使用,RMI将使您充分利用其强大功能。
RMI与现有原有系统及其他组件的连接的方式有:
- RMI可利用标准Java本机方法接口JNI与现有的和原有的系统相连接。RMI/JNI和RMI/JDBC相结合,可帮助我们利用RMI与目前使用非Java语言的现有服务器进行通信,而且在您需要时可扩展Java在这些服务器上的使用。RMI可帮助您在扩展使用时充分利用Java的强大功能。
- RMI还可利用标准JDBC包与现有的关系数据库连接。
RMI基本原理
RMI应用程序通常包括两个独立的程序:服务器程序和客户机程序。典型的服务器应用程序将创建多个远程对象,使这些远程对象能够被引用,然后等待客户机调用这些远程对象的方法。而典型的客户机程序则从服务器中得到一个或多个远程对象的引用,然后调用远程对象的方法。RMI为服务器和客户机进行通信和信息传递提供了一种机制。
在与远程对象的通信过程中,RMI使用标准机制:stub和skeleton。远程对象的stub担当远程对象的客户本地代表或代理人角色。调用程序将调用本地stub的方法,而本地stub将负责执行对远程对象的方法调用。在RMI中,远程对象的stub与该远程对象所实现的远程接口集相同。调用stub的方法时将执行下列操作:
- 初始化与包含远程对象的远程虚拟机的连接
- 对远程虚拟机的参数进行编组(写入并传输)
- 等待方法调用结果
- 解编(读取)返回值或返回的异常
- 将值返回给调用程序。
注意:为了向调用程序展示比较简单的调用机制,stub将参数的序列化和网络级通信等细节隐藏了起来。
在远程虚拟机中,每个远程对象都可以有相应的skeleton(从JDK 1.2开始无需使用skeleton)。Skeleton负责将调用分配给实际的远程对象实现。Skeleton在接收方法调用时执行下列操作:
- 解编(读取)远程方法的参数
- 调用实际远程对象实现上的方法
- 将结果(返回值或异常)编组(写入并传输)给调用程序
注意:stub和skeleton由rmic编译器生成。
利用RMI编写分布式对象应用程序需要完成以下工作:
- 定位远程对象。应用程序可使用两种机制中的一种得到对远程对象的引用。它既可用RMI的简单命名工具rmiregistry来注册它的远程对象,也可以将远程对象引用作为常规操作的一部分来进行传递和返回。
- 与远程对象通信。远程对象间通信的细节由RMI处理,对于程序员来说,远程通信看起来就像标准的Java方法调用。
- 给作为参数或返回值传递的对象加载类字节码。因为RMI允许调用程序将纯Java对象传给远程对象,所以,RMI将提供必要的机制,既可以加载对象的代码又可以传输对象的数据。在RMI分布式应用程序运行时,服务器调用注册服务程序以使名字与远程对象相关联。客户机在服务器上的注册服务程序中用远程对象的名字查找该远程对象,然后调用它的方法。
一个完整的RMI系统由以下几部分组成:
a) 远程服务的接口定义
b) 远程服务接口的具体实现
c) 桩(Stub)和框架(Skeleton)文件
d) 一个运行远程服务的服务器
e) 一个RMI命名服务,它允许客户端去发现这个远程服务
f) 类文件的提供者(一个HTTP或者FTP服务器)
g) 一个需要这个远程服务的客户端程序
基于上述RMI系统的通信过程为:方法调用从客户对象经占位程序(Stub)、远程引用层(Remote Reference Layer)和传输层(Transport Layer)向下,传递给主机,然后再次经传输层,向上穿过远程调用层和骨干网(Skeleton),到达服务器对象。占位程序扮演着远程服务器对象的代理的角色,使该对象可被客户激活。远程引用层处理语义、管理单一或多重对象的通信,决定调用是应发往一个服务器还是多个。传输层管理实际的连接,并且追追踪可以接受方法调用的远程对象。服务器端的骨干网完成对服务器对象实际的方法调用,并获取返回值。返回值向下经远程引用层、服务器端的传输层传递回客户端,再向上经传输层和远程调用层返回。最后,占位程序获得返回值。要完成上述步骤需要有以下几个步骤:
(1) 生成一个远程接口
(2) 实现远程对象(服务器端程序)
(3) 生成占位程序和骨干网(服务器端程序)
(4) 编写服务器程序
(5) 编写客户程序
(6) 注册远程对象
(7) 启动远程对象