RMI(Remote Method Invocation,远程方法调用)是 Java 提供的一种机制,使得在一个 JVM(Java 虚拟机)中的对象可以调用另一个 JVM 中对象的方法。简单来说,它允许不同计算机上的 Java 程序进行通信。RMI 主要应用于分布式计算中。

基本概念:

  • 远程接口:定义了远程对象的行为。远程接口必须继承 java.rmi.Remote 类,并且每个方法都需要抛出 java.rmi.RemoteException

  • 远程对象:实现了远程接口的对象。这个对象通常会被暴露到网络上,允许其他 JVM 调用它的方法。

  • RMI 注册表:是一个简单的名称服务,用来查找远程对象。它运行在服务器上,允许客户端根据对象名称查找远程对象。

工作原理:

  1. 创建远程接口:定义远程调用的方法。

  2. 实现远程对象:在服务器端实现远程接口并启动该对象。

  3. 注册远程对象:将远程对象注册到 RMI 注册表。

  4. 客户端调用:客户端通过 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 依然是一个有效的选择。