RMI(Remote Method Invocation,远程方法调用)是 Java 提供的一种机制,使得在一个 JVM(Java 虚拟机)中的对象可以调用另一个 JVM 中对象的方法。简单来说,它允许不同计算机上的 Java 程序进行通信。RMI 主要应用于分布式计算中。
基本概念:
远程接口:定义了远程对象的行为。远程接口必须继承
java.rmi.Remote
类,并且每个方法都需要抛出java.rmi.RemoteException
。远程对象:实现了远程接口的对象。这个对象通常会被暴露到网络上,允许其他 JVM 调用它的方法。
RMI 注册表:是一个简单的名称服务,用来查找远程对象。它运行在服务器上,允许客户端根据对象名称查找远程对象。
工作原理:
创建远程接口:定义远程调用的方法。
实现远程对象:在服务器端实现远程接口并启动该对象。
注册远程对象:将远程对象注册到 RMI 注册表。
客户端调用:客户端通过 RMI 注册表查找远程对象并调用它的方法。
示例:
假设我们有一个远程接口 Hello
和实现类 HelloImpl
。
1. 创建远程接口:
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Hello extends Remote {
String sayHello() throws RemoteException;
}
2. 实现远程对象
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class HelloImpl extends UnicastRemoteObject implements Hello {
protected HelloImpl() throws RemoteException {
super();
}
@Override
public String sayHello() throws RemoteException {
return "Hello, world!";
}
}
3服务器端代码:
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
public class Server {
public static void main(String[] args) {
try {
// 创建 RMI 注册表
LocateRegistry.createRegistry(1099);
// 创建远程对象
HelloImpl hello = new HelloImpl();
// 将对象绑定到 RMI 注册表
Naming.rebind("rmi://localhost/Hello", hello);
System.out.println("Server is ready.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
4. 客户端代码
import java.rmi.Naming;
public class Client {
public static void main(String[] args) {
try {
// 查找远程对象
Hello hello = (Hello) Naming.lookup("rmi://localhost/Hello");
// 调用远程方法
System.out.println(hello.sayHello());
} catch (Exception e) {
e.printStackTrace();
}
}
}
RMI 的优缺点:
优点:
简单的编程模型,容易理解和使用。
自动处理了网络通信、序列化、异常传递等复杂操作。
缺点:
基于 Java,客户端和服务器端都必须是 Java 程序。
性能和效率问题,尤其是网络延迟和序列化/反序列化的开销。
需要配置 RMI 注册表和网络环境。
RMI 在现代应用中使用得相对较少,随着 RESTful API、gRPC 等技术的兴起,越来越多的分布式系统选择这些替代方案。不过,对于 Java 生态内的分布式应用,RMI 依然是一个有效的选择。