当前位置: 首页 > news >正文

java RMI 技术介绍和实践

        在项目上发现了使用rmi技术,充电一波

RMI 概述

        RMI(Remote Method Invocation)是一种 Java 编程语言中的远程过程调用(RPC)协议,用于在不同的Java虚拟机(JVM)之间进行通信和交互。它允许远程计算机上的Java对象像本地对象一样进行访问和操作,从而使分布式应用程序的开发变得更加容易和方便。

RMI 基本思想

        RMI 基本思想是远程方法调用,即客户端调用某个方法,其本质是将这个方法的调用请求,发送给服务器,由服务器代为执行,且,服务器将执行结果回送客户端。

  • 对于客户端而言,RMI 只要求客户端针对方法本身,产生一种错觉:方法是在本地被调用的;
  • 对于服务器而言,RMI 相当于要处理一个来自客户端的“请求”;这个请求针对某个方法。

RMI 设计分析

客户端功能:

  1. 连接 RMI 服务器;
  2. 远程方法的消费者,从Registry获取远程方法的相关信息并且调用
  3. 等待服务器返回这个方法在服务器端执行的结果。

服务器端功能:

  1. 建立 RMI 服务器;
  2. 侦听客户端连接请求;
  3. 连接 RMI 客户端;
  4. 接受客户端发送过来的要执行的方法名称、实参等信息;找到这个需要代理执行方法,并反射机制执行该方法,并将方法执行的结果回传给客户端,断开与客户端的连接。

Registry:

        提供服务注册与服务获取。即Server端向Registry注册服务,比如地址、端口等一些信息,Client端从Registry获取远程对象的一些信息,如地址、端口等,然后进行远程调用。

工作流程:

  1. 首先,启动RMI Registry服务,启动时可以指定服务监听的端口,也可以使用默认的端口(1099);

  2. 其次,Server端在本地先实例化一个提供服务的实现类,然后通过RMI提供的Naming/Context/Registry等类的bindrebind方法将刚才实例化好的实现类注册到RMI Registry上并对外暴露一个名称;

  3. 最后,Client端通过本地的接口和一个已知的名称(即RMI Registry暴露出的名称),使用RMI提供的Naming/Context/Registry等类的lookup方法从RMI Service那拿到实现类。这样虽然本地没有这个类的实现类,但所有的方法都在接口里了,便可以实现远程调用对象的方法了;

Demo

定义一个接口

package com.cjian.rmi;import java.rmi.Remote;
import java.rmi.RemoteException;/*** @Author: cjian* @Date: 2023/11/8 10:17* @Des:*/
public interface PersonController extends Remote {// 注意这里必须抛出RemoteException,否则在查找服务的时候会提示 illegal remote method encountered 异常String queryName() throws RemoteException;
}

服务端有上面接口的具体实现,这里实现main方法运行

package com.cjian.rmi;import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;/*** @Author: cjian* @Date: 2023/11/8 10:17* @Des:*/
public class PersonControllerImpl extends UnicastRemoteObject implements PersonController {protected PersonControllerImpl() throws RemoteException {}@Overridepublic String queryName() {System.out.println("Receive request");return "My name's CJ";}public static void main(String[] args) {try {//创建服务端PersonController personController = new PersonControllerImpl();//注册到8888端口,也注册可以注册到别的机器上。LocateRegistry.createRegistry(8888);//绑定服务端到指定的地址,这里的localhost对应的上一步注册端口号的机器java.rmi.Naming.rebind("rmi://localhost:8888/" + PersonController.class.getName(), personController);System.out.println("Ready...");} catch (Exception e) {e.printStackTrace();}}
}

启动:

客户端调用

package com.cjian.rmi;import java.rmi.Naming;/*** @Author: cjian* @Date: 2023/11/8 10:21* @Des:*/
public class ClientTest {public static void main(String[] args) {try {//客户端去查找指定的服务PersonController personController = (PersonController) Naming.lookup("rmi://localhost:8888/" + PersonController.class.getName());//打印的结果应该是 My name's CJSystem.out.println(personController.queryName());} catch (Exception e) {e.printStackTrace();}}
}

测试结果:

另一种写法:

package com.cjian.rmi.custom;import java.rmi.Remote;
import java.rmi.RemoteException;/*** @Author: cjian* @Date: 2023/11/8 10:17* @Des:*/
public interface PersonController2 extends Remote {// 注意这里必须抛出RemoteException,否则在查找服务的时候会提示 illegal remote method encountered 异常String queryName() throws RemoteException;
}
package com.cjian.rmi.custom;import com.cjian.rmi.PersonController;import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;/*** @Author: cjian* @Date: 2023/11/8 10:17* @Des:*/
public class PersonControllerImpl2 implements PersonController {@Overridepublic String queryName() {System.out.println("Receive request");return "My name's CJ";}public static void main(String[] args) {try {//创建服务端PersonController personController = new PersonControllerImpl2();//注册到8888端口,也注册可以注册到别的机器上。UnicastRemoteObject.exportObject(personController, 8080);Registry registry = LocateRegistry.createRegistry(8888);registry.rebind(PersonController.class.getName(), personController);System.out.println("Ready...");} catch (Exception e) {e.printStackTrace();}}
}
package com.cjian.rmi.custom;import com.cjian.rmi.PersonController;import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;/*** @Author: cjian* @Date: 2023/11/8 10:21* @Des:*/
public class ClientTest2 {public static void main(String[] args) {try {Registry registry = LocateRegistry.getRegistry("localhost", 8888);PersonController personController = (PersonController) registry.lookup(PersonController.class.getName());System.out.println(personController.queryName());} catch (Exception e) {e.printStackTrace();}}
}

效果一样

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Redis 的几种集群对比
  • Vue2打包自定义文件命名规则CDN部署前端项目
  • pandas教程:Data Transformation 数据变换、删除和替换
  • C++ set map 的模拟实现
  • 蓝桥杯算法竞赛系列第十章·nSum问题的代码框架
  • 必看:阿里云99元服务器原价续费,你肯定不知道!
  • 互联网Java工程师面试题·Spring篇·第六弹
  • 第十一章《搞懂算法:聚类是怎么回事》笔记
  • 基于遗传算法的电器分类,基于GA的电器分类
  • 1 快速了解Paimon数据湖核心原理及架构
  • 机器人和自动化技术
  • 6.Spark共享变量
  • JavaScript客户端操作
  • 串口调试助手和网络调试助手使用总结
  • java split字符串作业
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • 2017 年终总结 —— 在路上
  • chrome扩展demo1-小时钟
  • Codepen 每日精选(2018-3-25)
  • crontab执行失败的多种原因
  • CSS居中完全指南——构建CSS居中决策树
  • JS字符串转数字方法总结
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • mac修复ab及siege安装
  • nodejs:开发并发布一个nodejs包
  • PHP CLI应用的调试原理
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • sublime配置文件
  • vue-cli3搭建项目
  • 动态魔术使用DBMS_SQL
  • 前端性能优化--懒加载和预加载
  • 深入浅出Node.js
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 应用生命周期终极 DevOps 工具包
  • ​水经微图Web1.5.0版即将上线
  • #、%和$符号在OGNL表达式中经常出现
  • #include
  • (01)ORB-SLAM2源码无死角解析-(56) 闭环线程→计算Sim3:理论推导(1)求解s,t
  • (03)光刻——半导体电路的绘制
  • (2024,Flag-DiT,文本引导的多模态生成,SR,统一的标记化,RoPE、RMSNorm 和流匹配)Lumina-T2X
  • (35)远程识别(又称无人机识别)(二)
  • (libusb) usb口自动刷新
  • (rabbitmq的高级特性)消息可靠性
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (四)c52学习之旅-流水LED灯
  • (算法二)滑动窗口
  • (文章复现)基于主从博弈的售电商多元零售套餐设计与多级市场购电策略
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • .gitignore文件设置了忽略但不生效
  • .NET Remoting学习笔记(三)信道
  • .NET 快速重构概要1
  • .net6 当连接用户的shell断掉后,dotnet会自动关闭,达不到长期运行的效果。.NET 进程守护
  • .NET基础篇——反射的奥妙