在项目上发现了使用rmi技术,充电一波
RMI 概述
RMI(Remote Method Invocation)是一种 Java 编程语言中的远程过程调用(RPC)协议,用于在不同的Java虚拟机(JVM)之间进行通信和交互。它允许远程计算机上的Java对象像本地对象一样进行访问和操作,从而使分布式应用程序的开发变得更加容易和方便。
RMI 基本思想
RMI 基本思想是远程方法调用,即客户端调用某个方法,其本质是将这个方法的调用请求,发送给服务器,由服务器代为执行,且,服务器将执行结果回送客户端。
- 对于客户端而言,RMI 只要求客户端针对方法本身,产生一种错觉:方法是在本地被调用的;
- 对于服务器而言,RMI 相当于要处理一个来自客户端的“请求”;这个请求针对某个方法。
RMI 设计分析
客户端功能:
- 连接 RMI 服务器;
- 远程方法的消费者,从Registry获取远程方法的相关信息并且调用
- 等待服务器返回这个方法在服务器端执行的结果。
服务器端功能:
- 建立 RMI 服务器;
- 侦听客户端连接请求;
- 连接 RMI 客户端;
- 接受客户端发送过来的要执行的方法名称、实参等信息;找到这个需要代理执行方法,并反射机制执行该方法,并将方法执行的结果回传给客户端,断开与客户端的连接。
Registry:
提供服务注册与服务获取。即Server端向Registry注册服务,比如地址、端口等一些信息,Client端从Registry获取远程对象的一些信息,如地址、端口等,然后进行远程调用。
工作流程:
-
首先,启动RMI Registry服务,启动时可以指定服务监听的端口,也可以使用默认的端口(1099);
-
其次,Server端在本地先实例化一个提供服务的实现类,然后通过RMI提供的Naming/Context/Registry等类的
bind
或rebind
方法将刚才实例化好的实现类注册到RMI Registry上并对外暴露一个名称; -
最后,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 {
}
@Override
public 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 CJ
System.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 {
@Override
public 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();
}
}
}
效果一样