前言

  对RMI接触的也比较早,基本上刚学完Java基础不久就机缘巧合遇到了。当时有尝试着去了解,但是没看到比较好的教程,而且对网络编程相关知识不太了解,看了不少文章,也没弄明白。现在对网络和I/O有了一定了解,理解起来也比较顺畅了。以下,是我对RMI的认识。

RMI的相关概念

  "In computing, the Java Remote Method Invocation (Java RMI) is a Java API that performs remote method invocation, the object-oriented equivalent of remote procedure calls (RPC), with support for direct transfer of serialized Java classes and distributed garbage-collection." ——维基百科

  上述定义指明几个点

  • RMI是Java用于调用远程方法的API ——①属于Java  ②指的是一个API,不是协议或者其他什么东西
  • 相当于面向对象版的RPC —— RPC是远程过程调用(面向过程)
  • 支持直接传输可序列化的Java类 ——①传输的类是方法调用需要的参数和返回值,而不是实现类,实现类的方法在服务器执行。
  • 支持分布式垃圾回收(暂未涉猎)

远程调用

  远程调用并不是加载远程的类到本地执行,而是通过传递方法参数到服务器,让服务器执行相应的方法并返回结果给客户端。

网络协议与IO

  RMI所指的远程调用,说的其实是从一个JVM的对象调用另一个JVM环境下对象方法的过程。两个JVM可以在不同的主机上,也可以在同一台主机上。如果在不同主机上,则方法调用必然需要网络传输,网络传输则必然与Socket通信以及相关的通信协议挂钩,RMI用的底层协议是JRMIP。值得一提的是,使用RMI这个API的好处就是,用户不需要实现底层的网络通信与IO,或者说网络传输对用户来说是透明的。

远程接口

  客户端和服务端都有的接口,只不过接口的实现类在服务端。

RMI的工作原理

  

  值得一提的是,我在学习RMI的时候,故我根据理解画了这张图。书上讲到需要用rmic指令生成stub和skeleton。但是实际上,Java后面已经废除了这种方式,skeleton被认为不再需要,但是服务器仍然有一些东西负责skeleton的行为(谁负责,暂不清楚,尚未了解底层实现)。而stub可以动态生成。所以用这张图理解RMI还是没问题的。

RMI远程服务的实现

相关概念

Remote

  java.rmi.server包下的定义的接口,远程接口必须继承与RMI的Remote接口,表明其远程接口的身份。

RMI registry

  RMI的注册表服务,服务器需要将对应的服务注册到注册表上,此操操作将会绑定对应服务的stub(存根)。客户端会根据服务器的IP地址找到服务器,然后在服务器的注册表上找对应的存根。

UnicastRemoteObject

  远程接口的实现类必须继承此类,以用于生成与底层JRMP协议相关的通信对象,以及用于与通信对象连接的stub(存根)。

服务端实现步骤

  1. 定义远程接口

    定义一个接口,继承于Remote接口。注意,定义的方法需要抛出RemoteException。因为网络和I/O是不安全的,必须让客户意识到这点,做相应的异常处理准备。

  2. 定义远程接口实现

    定义一个类实现上述接口,并继承UnicastRemoteObject。可在此类,或其他类中的main方法中,注册服务到注册表表。

    Naming.rebind("serviceName", service);   

  3. 启动RMI registry注册表服务

    利用命令行启动。启动命令所在的目录必须能够访问到你的类。最好在实现类目录启动。

    %rmiregistry           

  4. 开启远程服务(注册服务到注册表)

    执行,带有注册操作的类。

客户端实现步骤

  1. 定义远程接口

    与服务端的接口相同,直接拷贝过来即可。

  2. 定义访问远程接口的类

    客户端需要定义一个类,用于连接到服务端的注册表,根据服务的相关信息查找并获取stub(存根)。

    Naming.lookup("rmi://ip:port/serviceName");   

   3. 根据stub访问远程接口方法。

RMI样例代码

文件图

注:在单机环境下模拟,客户端服务端在不同的文件夹。

服务端

MyRemote.java

import java.rmi.*;

public interface MyRemote extends Remote {
public String sayHello() throws RemoteException;
}

MyRemoteImpl.java

import java.rmi.*;
import java.rmi.server.*; public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {
//实现远程方法
public String sayHello() {
return "Server says, 'Hey'";
} public MyRemoteImpl() throws RemoteException { } //主方法,注册服务到注册表
public static void main(String[] args) {
try {
//创建远程对象
MyRemote service = new MyRemoteImpl();
//绑定到注册表
//rebind方法会覆盖同名方法,相当于先unbind再bind.
Naming.rebind("RemoteHello", service);
} catch(Exception e) {
e.printStackTrace();
}
}
}

启动RMI Registry注册表服务,注意,此命令没有任何响应,就是开启成功了,不要关闭此弹窗

启动服务,开启另一个控制台,运行主程序。此主程序同样没有任何输出。

客户端

MyRemote同上

MyRemoteClient.java

import java.rmi.*;

public class MyRemoteClient {
public static void main(String[] args) {
new MyRemoteClient().go();
} public void go() {
try {
//查找对应服务,并获取到存根
MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1/RemoteHello");
//利用存根调用接口方法
String s = service.sayHello();
//输出返回值
System.out.println(s);
} catch(Exception e) {
e.printStackTrace();
}
}
}

启动客户端,开启另一个控制台,启动客户端主程序

为什么远程接口可直接调用Stub

  远程接口能直接调用stub,那很明显,stub就是远程接口的实现类。前面我们提到了,用rmic命令工具生生成stub的方式已经被废除了。stub可以动态生成。但是使用rmic命令工具还是可以生成_stub的class文件。虽然有相关的警告。

我们可以用反编译工具,来查看其源码。我使用的是jd-gui。

即,stub确实就是远程接口的实现类。注意,只是语法上实现,真正的实现在服务端。stub算是一个代理,让客户端可以像操作实现类那样操作stub,好像实现类就在本地一样。

【杂谈】对RMI(Remote Method Invoke)的认识的更多相关文章

  1. K:java中的RMI(Remote Method Invocation)

    相关介绍:  RMI全称是Remote Method Invocation,即远程方法调用.它是一种计算机之间利用远程对象互相调用,从而实现双方通讯的一种通讯机制.使用这种机制,某一台计算机(虚拟机) ...

  2. Spring Remoting: Remote Method Invocation (RMI)--转

    原文地址:http://www.studytrails.com/frameworks/spring/spring-remoting-rmi.jsp Concept Overview Spring pr ...

  3. java的RMI(Remote Method Invocation)

    RMI 相关知识RMI全称是Remote Method Invocation-远程方法调用,Java RMI在JDK1.1中实现的,其威力就体现在它强大的开发分布式网络应用的能力上,是纯Java的网络 ...

  4. bubbo调用Failed to invoke remote method异常解决

    bubbo调用服务异常: com.alibaba.dubbo.rpc.RpcException: Failed to invoke remote method: getPlanFlowInfo, pr ...

  5. com.alibaba.dubbo.rpc.RpcException: Failed to invoke remote method解决方法

    报错日记: Caused by: com.alibaba.dubbo.rpc.RpcException: Failed to invoke remote method: getUserAuthLeve ...

  6. Spring之RMI 远程方法调用 (Remote Method Invocation)

    RMI 指的是远程方法调用 (Remote Method Invocation) 1. RMI的原理: RMI系统结构,在客户端和服务器端都有几层结构. 方法调用从客户对象经占位程序(Stub).远程 ...

  7. 遇到的问题之“Dubbo 直连 Invoke remote method timeout 问题!”

    Dubbo 直连 Invoke remote method timeout 问题!   在测试环境消费者直连服务端进行测试时, 其中一个RPC接口抛出一个错误, 如下: Caused by: com. ...

  8. Java远程方法调用(Remote Method Invocation,RMI)

    Java RMI简介: 它是Java的一个核心API和类库,允许一个Java虚拟机上运行的Java程序调用不同虚拟机上运行的对象中的方法,即使这两个虚拟机运行于物理隔离的不同主机上. Java RMI ...

  9. RMI(Remote Method Invocation ) 概念恢复

    1.RMI是远程方法调用的简称,像其名称暗示的那样,它能够帮助我们查找并执行远程对象,通俗的说,远程调用就像一个class放在A机器上,然后在B机器中调用这个class的方法. 2.EMI术语 在研究 ...

随机推荐

  1. debian7(wheezy)升级安装mercurial hg最新版2.8-RC,解决tortoisehg2.9.2不能使用。

    debian&(wheezy)之前的仓库版本是2.2.2.  注: 本文以 # 为开始的行是工作在root下的模式,在终端显示为root的提示符# ,用户目录的($:)需要切换到root(使用 ...

  2. letcode code]Maximum Subarray

    1 题目: Find the contiguous subarray within an array (containing at least one number) which has the la ...

  3. ip网段变更

    背景 公司网络跟集团靠拢,先走第一步:IP网段变更.从XX网段切换到OO网段 方法 1. 准备工作 a. 保证IPMI连接正常 b. 获得新IP并核对对应主机名.旧IP是否相符 2. 确认网卡名称 # ...

  4. 扩展 StackExchange.Redis 支持实体

    一.StackExchange.Redis StackExchange.Redis是由Stack Overflow开发的C#语言Redis客户端,使用广泛,本文针对 StackExchange.Red ...

  5. Linux下安装MySQL以及一些小坑

    第一次写博客,各位凑合着看吧(假装有人看). 我这里使用的是centos7. 1.首先打开终端,查看有没有安装过MySQL: [root@localhost lyp]# rpm -qa | grep ...

  6. day02 基本数据类型与运算符

    day02 1.基本数据类型 2.算术运算符 +,-,*,/,%,++,-- 3.赋值运算符 =,+=,-=,*=,/=,%= 4.关系运算符 +=,-=,*=,/=,%=  结果是boolean类型 ...

  7. 一个简单文本分类任务-EM算法-R语言

    一.问题介绍 概率分布模型中,有时只含有可观测变量,如单硬币投掷模型,对于每个测试样例,硬币最终是正面还是反面是可以观测的.而有时还含有不可观测变量,如三硬币投掷模型.问题这样描述,首先投掷硬币A,如 ...

  8. 初探日志框架Logback

    一. 背景 最近因为学习项目时需要使用logback日志框架来打印日志, 使用过程中碰到很多的疑惑, 而且需要在控制台打印mybatis执行的sql语句, 于是决定沉下心来 研究一下logback的使 ...

  9. [ActionScript 3.0] 加载子swf需要指定应用程序域

    var ldr:Loader = new Loader(); ldr.load(new URLRequest("assets/test.swf")); 如上,如果在flash帧上写 ...

  10. Swift5 语言指南(二十七) 访问控制

    访问控制限制从其他源文件和模块中的代码访问部分代码.此功能使您可以隐藏代码的实现细节,并指定一个首选接口,通过该接口可以访问和使用该代码. 您可以为各个类型(类,结构和枚举)以及属于这些类型的属性,方 ...