RMI原理及流程
前言
学习过程中发现有很多“概念性”的东西,导致大段的文字说明出现。
java这门语言,我自认为很多“概念性”的东西其实源自于它的语言特性像继承多态这种,所以其实可以不用说的这么繁琐。
以后我记笔记的时候应该要尝试怎么用最简单的语言去描述,并且阅读源码才是最重要的。
学习过程中愈加感觉到,耐心,细心这两点尤其重要!
初识JAVA RMI
定义
RMI(Remote Method Invocation)为远程方法调用,是允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法。 这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中。
Java RMI:Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能简化远程接口对象的使用。
https://blog.csdn.net/xinghun_4/article/details/45787549
流程
整个RMI的流程分为三个部分,RMIServer , RMIClient , RMIRegister,其中RMIRegister(RMIService)担任中间人的身份
服务端( RMIServer ) 会将自己提供的服务的实现类交给这个中间人 , 并公开一个名称 . 任何客户端( RMIClient )都可以通过公开的名称找到这个实现类 , 并调用它
这样做避免了服务端和客户端资源的直接交互,也使得客户端能更好地查找要使用的对象。解决了一部分安全问题。
关于Stub存根:
在 JVM 之间通过 RMI 进行远程对象的调用时,并不是简单地直接将远程对象复制一份传递给客户端,而是传递了一个远程对象 Stub ,Stub 基本上相当于是远程对象的引用或者 代理 (java 在 RMI 中用到了代理模式)。Stub 对象对于我们是透明的,客户端可以像调用本地方法一样直通过 Stub 对象来调用远程的方法。
交互时序图:
实现一个简单的rmi应用
定义一个远程接口
准备一个接口,让客户端通过这个接口来访问服务
1 | public interface Hello extends Remote { |
在 Java 中 , 如果一个类继承了 java.rmi.Remote 接口 , 那么该类将成为一个服务端的远程对象 , 供客户端访问并提供一定的服务
JavaDoc描述:Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口。任何远程对象都必须直接或间接实现此接口。只有在“远程接口”(扩展java.rmi.Remote 的接口)中指定的这些方法才可被远程调用。
extends了Remote接口的类或者其他接口中的方法若是声明抛出了RemoteException异常,则表明该方法可被客户端远程访问调用。
远程接口实现类
1 | public class HelloImpl extends UnicastRemoteObject implements Hello { |
远程对象必须实现java.rmi.server.UniCastRemoteObject类,这样才能保证客户端访问获得远程对象时,该远程对象将会把自身的一个拷贝以Socket的形式传输给客户端,此时客户端所获得的这个拷贝称为“存根Stub”,而服务器端本身已存在的远程对象则称之为“骨架Skeleton”。
其实此时的存根是客户端的一个代理,用于与服务器端的通信,而骨架也可认为是服务器端的一个代理,用于接收客户端的请求之后调用远程方法来响应客户端的请求。
其实 , 与其说是客户端和服务端进行交互 , 不如说是 客户端代理( Stub ) 和 服务端代理( Skeleton ) 在进行交互 。
在 JDK1.2 以后的 RMI 中 , 可以通过反射API 直接将请求发送给真实类 , 不再需要 Skeleton 来做中转了
服务端
1 | public class RmiServer { |
RMIService ( RMIRegister ) 服务的默认端口为 : 1099
客户端
1 | public class RmiClient { |
类继承图
在我中间编写demo的时候出现了一些小问题,Hello hello = (Hello) Naming.lookup("rmi://localhost:1099/hello");
这里是一个关于接口的知识点,太久所以有所遗忘。接口类型用来声明一个接口类型的引用变量
https://www.cnblogs.com/xiaoheliu1024/p/10918017.html
通讯流程分析
tcp.stream eq 41
tcp.stream eq 49
一共建立了两次tcp连接,客户端先连接Registry,寻找Hello对象,Registry返回一个序列化数据,就是Hello对象,客户端反序列化这个数据,发现是远程对象,然后根据封装的ip端口建立新的tcp连接,并且进行远程方法调用
服务端给返回给客户端的Hello类,其中为反序列化数据,以及其他的rmi中的类
也就是rmi register只会返回一个注册了的远程对象,然后服务端执行远程命令调用它而已
参考
https://www.guildhab.top/2020/03/java-rmi-ldap-%e6%b5%81%e7%a8%8b%e5%88%86%e6%9e%90/