学习RMI的原理和使用
参考:https://blog.csdn.net/kingcat666/article/details/78578578
一、RMI
RMI(Remote Method Invocation,远程方法调用)。通过RMI技术,某一个本地的JVM可以调用存在于另外一个JVM中的对象方法,就好像它仅仅是在调用本地JVM中某个对象方法一样。
二、RMI的适用场景
RMI是基于JAVA语言的,也就是说在RMI技术框架的描述中,只有Server端使用的是JAVA语言并且Client端也是用的JAVA语言,才能使用RMI技术RMI适用于两个系统都主要使用JAVA语言进行构造,不需要考虑跨语言支持的情况。并且对两个JAVA系统的通讯速度有要求的情况。
RMI 是一个良好的、特殊的RPC实现:使用JRMP协议承载数据描述,可以使用BIO和NIO两种IO通信模型。RMI框架是可以在大规模集群系统中使用的。
三、RMI的基本框架
从设计角度上讲,JAVA采用的是三层结构模式来实现RMI。在整个体系结构中,有如下几个关键角色构成了通信双方:
1.客户端:
1)桩(StubObject):远程对象在客户端上的代理;
2)远程引用层(RemoteReference Layer):解析并执行远程引用协议;
3)传输层(Transport):发送调用、传递远程方法参数、接收远程方法执行结果。
2.服务端:
1)骨架(Skeleton):读取客户端传递的方法参数,调用服务器方的实际对象方法,并接收方法执行后的返回值;
2)远程引用层(Remote ReferenceLayer):处理远程引用语法之后向骨架发送远程方法调用;
3)传输层(Transport):监听客户端的入站连接,接收并转发调用到远程引用层。
3.注册表(Registry):以URL形式注册远程对象,并向客户端回复对远程对象的引用。
在实际的应用中,客户端并没有真正的和服务端直接对话来进行远程调用,而是通过本地JVM环境下的桩对象来进行的。
远程调用过程:
1)客户端从远程服务器的注册表中查询并获取远程对象引用。当进行远程调用时,客户端首先会与桩对象(Stub Object)进行对话,而这个桩对象将远程方法所需的参数进行序列化后,传递给它下层的远程引用层(RRL);
2)桩对象与远程对象具有相同的接口和方法列表,当客户端调用远程对象时,实际上是由相应的桩对象代理完成的。远程引用层在将桩的本地引用转换为服务器上对象的远程引用后,再将调用传递给传输层(Transport),由传输层通过TCP协议发送调用;
3)在服务器端,传输层监听入站连接,它一旦接收到客户端远程调用后,就将这个引用转发给其上层的远程引用层;
4)服务器端的远程引用层将客户端发送的远程应用转换为本地虚拟机的引用后,再将请求传递给骨架(Skeleton);
5)骨架读取参数,又将请求传递给服务器,最后由服务器进行实际的方法调用。
结果返回过程:
1)如果远程方法调用后有返回值,则服务器将这些结果又沿着“骨架->远程引用层->传输层”向下传递;
2)客户端的传输层接收到返回值后,又沿着“传输层->远程引用层->桩”向上传递,然后由桩来反序列化这些返回值,并将最终的结果传递给客户端程序。
从技术的角度上讲,有如下几个主要类或接口扮演着上述三层模型中的关键角色:
1)注册表:java.rmi.Naming和java.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
四、RMI的开发流程
作为一般的RMI应用,JAVA为我们隐藏了其中的处理细节,而让开发者有更多的精力和时间花在实际的应用中。开发RMI的步骤如下所述:
1.服务端:
1)定义Remote子接口,在其内部定义要发布的远程方法,并且这些方法都要Throws RemoteException;
2)定义远程对象的实现类,通常有两种方式:
a. 继承UnicastRemoteObject或Activatable,并同时实现Remote子接口;
b. 只实现Remote子接口和java.io.Serializable接口。
3)编译桩(在JAVA 1.5及以后版本中,如果远程对象实现类继承了UnicastRemoteObject或Activatable,则无需此步,由JVM自动完成。否则需手工利用RMIC工具编译生成此实现类对应的桩类,并放到和实现类相同的编译目录下);
4)启动服务器:依次完成注册表的启动和远程对象绑定。另外,如果远程对象实现类在定义时没有继承UnicastRemoteObject或Activatable,则必须在服务器端显式的调用UnicastRemoteObject类中某个重载的exportObject(Remote remote)静态方法,将此实现类对象导出成为一个真正的远程对象。
2.客户端:
1)定义用于接收远程对象的Remote子接口,只需实现java.rmi.Remote接口即可。但要求必须与服务器端对等的Remote子接口保持一致,即有相同的接口名称、包路径和方法列表等。
2)通过符合JRMP规范的URL字符串在注册表中获取并强转成Remote子接口对象;
3)调用这个Remote子接口对象中的某个方法就是为一次远程方法调用行为。