0x01 什么是Java RMI? Java RMI(Java Remote Method Invocation),即Java远程方法调用。是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。能直接传输序列化后的Java对象和分布式垃圾收集 。它的实现依赖于Java虚拟机 (JVM),因此它仅支持从一个JVM到另一个JVM的调用
看到这里你知道什么是Java RMI了吗?我比较笨,没看懂。
没关系,我又找了一篇博文,来看下它给出的解释:RMI,是Remote Method Invocation(远程方法调用)的缩写,即在一个JVM中java程序调用在另一个远程JVM中运行的java程序,这个远程JVM既可以在同一台实体机上,也可以在不同的实体机上,两者之间通过网络进行通信。
到这里,好像能看懂点了,RMI顾名思义-远程调用,远程指什么?调用什么?远程指的是同一台主机上不同JVM之间的远程或者两台主机上的JVM的远程,调用的是JVM上运行的程序。
0x02 通过一个例子来理解下 RMI包括以下三个部分:
Registry: 提供服务注册与服务获取。即Server端向Registry注册服务,比如地址、端口等一些信息,Client端从Registry获取远程对象的一些信息,如地址、端口等,然后进行远程调用。
Server: 远程方法的提供者,并向Registry注册自身提供的服务
Client: 远程方法的消费者,从Registry获取远程方法的相关信息并且调用
以下例子根据参考链接改编,一个远程接口IGoods,一个实现接口的类Goods,一个注册远程对象的类PutOnSaleServer,一个客户端调用的类ShoppingClient:
IGoods:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.rmi.Remote;import java.rmi.RemoteException;public interface IGoods extends Remote { public double add (double a, double b) throws RemoteException ; public double subtract (double a, double b) throws RemoteException ; public String shopping (String person) throws RemoteException ; }
Goods:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import java.rmi.RemoteException;import java.rmi.server.UnicastRemoteObject;public class Goods extends UnicastRemoteObject implements IGoods { private int numberOfComputations; protected Goods () throws RemoteException { numberOfComputations = 0 ; } @Override public double add (double a, double b) throws RemoteException { numberOfComputations++; System.out.println("Number of computations performed so far = " + numberOfComputations); return (a+b); } @Override public double subtract (double a, double b) throws RemoteException { numberOfComputations++; System.out.println("Number of computations performed so far = " + numberOfComputations); return (a-b); } @Override public String shopping (String person) throws RemoteException { System.out.println("Number of computations performed so far = " + numberOfComputations); System.out.println(person + "is Shopping" ); String a = person + " is shopping!" ; return a; } }
PutOnSaleServer.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry;public class PutOnSaleServer { public static void main (String[] args) { try { IGoods goods = new Goods(); LocateRegistry.createRegistry(1099 ); Registry registry = LocateRegistry.getRegistry(); registry.bind("Compute" , goods); System.out.println("货物上架完成" ); } catch (Exception e) { e.printStackTrace(); } } }
ShoppingClient.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry;public class ShoppingClient { public static void main (String[] args) { try { Registry registry = LocateRegistry.getRegistry("localhost" ); IGoods goods = (IGoods) registry.lookup("Compute" ); System.out.println(goods.shopping("小陈" )); } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
现在看完例子,可以梳理下:
货物-远程对象、备货员-server、货架-骨架;
消费者-client、购买凭证-存根;
小货仓-RMI Registry
可以把Java RMI理解成地铁站的无人售货机
1、备货员先将货物信息存到小货仓 ,保证售货机有货物
2、消费者购买需要在显示屏的找到要买的物品然后进行支付,支付完成获取到了购买凭证
3、消费者通过购买凭证,告诉售货机我要获取某个货物,然后售货机在货架 上找到目标货物推到售货口,消费者通过可以获取到货物。
0x03 扩展 RMI原理
将可以远程调用的对象进行序列化,然后绑定到RMI Server(被调方,运行者)中作为存根(stub)
RMI Client 会先去下载stub反序列化 然后发起client调用,RMI 底层(RMI Interface Layer & Transport Layer)会讲请求参数封装发送到RMI Server
RMI Server 接收到封装的参数,传递给骨架(skeleton),由桩解析参数并且以参数调用对应的存根(stub)方法。
存根方法在RMI Server执行完毕之后,返回结果将被RMI底层封装并传输给RMI Client(也就是主调方,调用者)
这里有一点需要注意:RMI是基于序列化和反序列化的,远程对象在进行注册时,序列化作为存根,客户端调用的时候会把序列化后的对象进行反序列化再调用。
参考链接:
https://www.jianshu.com/p/de85fad05dcb
https://www.jianshu.com/p/5c6f2b6d458a
https://segmentfault.com/a/1190000016598069
https://blog.csdn.net/qq_28081453/article/details/83279066
https://www.cnblogs.com/lvyahui/p/5425507.html