企业神奇中间件-RPC之RMI(上) No.99

我知道你们周末不喜欢学习,但是我不管我就是要写,然后那你为什么还不赶紧左上角退出,啊哈哈哈哈哈哈!!!!!

说了那么久,到底什么是 RMI (Java Remote Method Invocation)呢?我们来看看维基百科的解释。

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.

emmm....,就是一个专门给 Java 提供的一个远程方法调用,以及进行实现 RPC 的一个 Java API,可以用来远程传输序列化类,以及实现分布式垃圾回收。完全obbqk,咱今天也分成几个阶段来看看RMI,Java Remote Method Invocation,Java 远程方法调用。具体是怎么玩的,怎么去使用它,又是什么原理。


说走咱就走啊,仅需体验三番钟,你揍会甘我一样,爱上介款 RPC 。 首先,看到这个链接。https://github.com/CallMeDJ/BigBanana-rpc.git

小心翼翼打开命令行终端,就那么git clone 一下。

贴心的我已经为你准备好了,你拷贝一下就行了,当然你要是没有 git 那就下载一个。

git clone https://github.com/CallMeDJ/BigBanana-rpc.git

然后用 JetBrains 的 IntelliJ IDEA import 一下,喏就这个Import Project,疯狂点下一步就好了。

等 IDEA 的界面打开后,然后右键点一下 Provider 的 Run 'Provider.main()'。

再右键点一下 Consumer 的 Run 'Consumer.main()'.

然后在 console 控制台,瞎打一些东西。然后用全身的力气按一下 Enter ,你会发现,咦,发现有一些数字回显出来。喔雪特你这么这么厉害??恭喜恭喜,你学会了RMI了。


emmm...好了,欢迎大家来到 RMI 第二层,上套路,讲代码,这上边这玩意怎么写出来的呢?

Service

首先定义一个服务 HelloService ,有一个名字叫 hello 的方法,返回一个 Integer 。

ServiceImpl

实现它!HelloServiceImpl 实现了 HelloService 的 hello 方法,直接返回字符串的 hashCode。

至于为什么要 继承 UnicastRemoteObject 呢。文档上的注释是这样的。用来曝露一个拥有对象引用,然后用 JRMP 协议沟通的远程对象。当然看不懂也没关系,就当没看见继续往下走。

/**
 * Used for exporting a remote object with JRMP and obtaining a stub
 * that communicates to the remote object.
 *

Provider

定义一个 Provider,用来对外暴露服务。

先初始化一个 HelloService 服务。

HelloService helloService  = new HelloServiceImpl();

生成一个注册表中心,用来将服务注册到这个地方,注意这里一定要先写,不然后边的服务就没法注册上来了。

Registry registry = LocateRegistry.createRegistry(8888);

将初始化完的服务,注册到注册中心中,这样,其他地方就可以通过注册中心获取到这个服务啦。

Naming.bind("rmi://127.0.0.1:8888/hello",helloService);

线程池的作用是避免应用被关掉,关键代码其实就上边那三行。

Consumer

好了,轮到 Consumer 了。

啦。

寻找一下注册中心。

Registry registry = LocateRegistry.getRegistry(8888);

把那个名字叫 hello 的服务找出来

HelloService masterService = (HelloService)registry.lookup("hello");

把当前 console 的那行值取出来,然后调用一下 HelloService 的服务,打印到 console。

String command = scanner.nextLine();
System.out.println(masterService.hello(command));

完美~你可以写自己基于 RMI 的服务了。随便找个地方搞一个注册中心,注册一大堆服务上去,其他地方就可以通过这个注册中心调用了了。


好了,欢迎大家来到 RMI 第三层,上原理,讲设计。好了,能耐心看到这里的,估计还是对这个技术有点想了解,那么我们继续讲,关于这个 RMI 技术的原理。

还是回到这个图,我们可以看到其实这个架构还是蛮简单的。首先 RMI 是基于 socket 技术进行网络通讯的。其次本地调用的是一个叫 Client stub (存根),而这个存根跟客户端是处于同一 JVM 的。第三 Server 端其实也有一个一模一样的存根,从技术上来讲,这两个存根里边的内容是一摸一样的,只是从 Server 端下载到了 Client 端。

RMI技术有两种使用方式,分别是继承 UnicastRemoteObject 的 由服务端直接提供服务对象类,以及继承 Activatable 的由注册中心提供激活的服务对象的方式。

第一种:

1、启动一个注册中心,这个注册中心是用 rmi 协议的,可以启动在本地的JVM也可以启动在其他地方。都是使用这个。这就是 RMI 强大的地方所在了,不仅仅 Consumer 和 Provider 可以远程,连注册中心都既可以运行在本地,也可以运行在远程。

LocateRegistry.createRegistry(8888);

2、Provider 本地启动一个 SocketServer ,用来进行服务提供。找到注册中心,然后向注册中心,以某个服务名字(比如 hello) 将自己注册到注册中心中,本地保留一个 stub 存根。

3、Consumer 找到注册中心,找到后寻求某个服务名字(比如 hello),得到服务端 Provider 的 socket 地址,其实也就是 ip 和 端口。

4、Consumer 用 socket 调用 Provider ,请求某个服务,Provider 用 JRMP(Java Remote Method Protocol)把本地服务的整个 Java 对象进行序列化打个大包,然后写到 socket 中。

5、Consumer 拿到这个对象流后呢,用 JRMP 进行反序列化,然后创建一个代理对象,交给调用方。

6、调用方拿着这个代理,进行本地调用。

好了,这就结束了第一种了。我们看到上边的第6点,其实这些远程调用并不是远程调用,只是远程把整个对象下载到本地,然后在本地跑这些方法。所以呢,你如果觉得每次都 hold 住这个代理,就可以了,那你就错了,一旦 Provider 有任何变更,你这样干的话,是获取不到最新的服务的。

虽然我感觉你的听得云里雾里,但是我不管,我就继续来说说第二种吧。。第二种会直接把类文件放到注册中心,然后在恰当的实际进行"激活"。什么叫激活呢,我的理解就是对类进行初始化,然后用序列化的方式交给调用方。

1、启动一个注册中心,这个注册中心是用 rmi 协议的,可以启动在本地的JVM也可以启动在其他地方。都是使用这个。这就是 RMI 强大的地方所在了,不仅仅 Consumer 和 Provider 可以远程,连注册中心都既可以运行在本地,也可以运行在远程。

LocateRegistry.createRegistry(8888);

2、Provider 初始化一个对象,然后类文件和自己的激活ID,激活组ID都放到注册中心。

3、Consumer 找到注册中心,找到后寻求某个激活ID,激活组ID的服务,请求进行存根请求。

4、Consumer 用 socket 从请求注册中心取得存根,注册中心对类进行初始化(激活),然后 用 JRMP(Java Remote Method Protocol)把激活后的的整个 Java 对象进行序列化打个大包,然后写到 socket 中。

5、Consumer 拿到来自注册中心的这个对象流后呢,用 JRMP 进行反序列化,然后创建一个代理对象,交给调用方。

6、调用方拿着这个代理,进行本地调用。

综上所述,RMI 就是把类下载到本地跑一波。


欢迎大家来到 RMI 第四层,讲源码。好了,下面很枯燥很枯燥,都是源码,不开心的可以退出了,抓紧时间。要是不想退出,来都来了,看看呗反正也不吃亏。

算了,下次再说了,我要去吃饭了。有人问我既然不写了为什么不删掉上边那段话,我觉得既然字被打出来了那就是有生命的,把它删掉好像把它杀了似的,不忍心。。。

原文发布于微信公众号 - 一名叫大蕉的程序员(DaBananaTalk)

原文发表时间:2018-05-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏xingoo, 一个梦想做发明家的程序员

Spark源码分析 之 Driver和Excutor是怎么跑起来的?(2.2.0版本)

今天抽空回顾了一下Spark相关的源码,本来想要了解一下Block的管理机制,但是看着看着就回到了SparkContext的创建与使用。正好之前没有正式的整理...

2067
来自专栏Java帮帮-微信公众号-技术文章全总结

大文件拆分方案的Java实践【面试+工作】

大文件拆分问题涉及到io处理、并发编程、生产者/消费者模式的理解,是一个很好的综合应用场景,为此,花点时间做一些实践,对相关的知识做一次梳理和集成,总结一些共性...

1324
来自专栏Leetcode名企之路

【java】CountDownLatch运用场景(1)

CountDownLatch也叫闭锁,使得一(多)个主线程必须等待其他线程完成操作后再执行。 使用的方式是:CountDownLatch内部维护一个计数器,主线...

701
来自专栏Golang语言社区

论获取缓存值的正确姿势

论获取缓存值的正确姿势 cache 时至今日,大家对缓存想必不在陌生。我们身边各种系统中或多或少的都存在缓存,自从有个缓存,我们可以减少很多计算压力,提高应用程...

3618
来自专栏代码散人

如何用kotlin开发同时支持iOS和Android的库

虽说kotlin-native可以支持链接到c,java,objective-c等语言,甚至可以进行原生开发,但是在使用的过程中并不友好,配置繁琐且api相对生...

952
来自专栏java工会

Java 11 新功能来了!

1844
来自专栏小灰灰

Quick-Task 动态脚本支持框架之使用介绍篇

文章链接:https://liuyueyi.github.io/hexblog/2018/07/19/180719-Quick-Task-动态脚本支持框架之使用...

762
来自专栏java一日一条

分布式通信的几种方式

目前的分布式架构主要由corba和JavaEE搭建,JavaEE优点是跨平台,开发成本低、周期短,不需要学习IDL语言;CORBA的优点是服务器响应速度更快。决...

2842
来自专栏云计算

Go 微服务第 9 章:基于 RabbitMQ 和 AMQP 进行消息传递

原文地址:https://dzone.com/articles/go-microservices-blog-series-part-9-messaging-wi...

7789
来自专栏编程

Java面试中问及Hibernate与MyBatis的对比,在这里做一下总结

我是一名java开发人员,hibernate以及mybatis都有过学习,在java面试中也被提及问道过,在项目实践中也应用过,现在对hibernate和myb...

22910

扫码关注云+社区