1. 概述

当两个JVM需要通信时,Java RMI是可选方案之一。本文将通过一个简单示例演示Java RMI技术的核心用法。

2. 创建服务器

创建RMI服务器需要两个步骤:

  1. 定义客户端/服务器通信的接口
  2. 实现该接口

2.1. 定义契约

首先创建远程对象接口,该接口需继承java.rmi.Remote标记接口。接口中声明的每个方法都必须抛出java.rmi.RemoteException

public interface MessengerService extends Remote {
    String sendMessage(String clientMessage) throws RemoteException;
}

⚠️ 注意:RMI支持完整的Java方法签名规范,但参数类型必须实现java.io.Serializable

后续章节将说明客户端和服务器如何使用此接口:

  • 服务器端需创建实现类(称为远程对象)
  • 客户端则由RMI库动态生成实现(称为存根Stub)

2.2. 实现

实现远程接口(即远程对象):

public class MessengerServiceImpl implements MessengerService { 
 
    @Override 
    public String sendMessage(String clientMessage) { 
        return "Client Message".equals(clientMessage) ? "Server Message" : null;
    }

    public String unexposedMethod() { /* code */ }
}

✅ 实现要点:

  1. 方法声明中省略了throws RemoteException(远程对象通常不直接抛出此异常)
  2. 保持实现类与RMI解耦
  3. 接口中未声明的方法(如unexposedMethod)对客户端不可见

3. 注册服务

创建远程实现后,需将远程对象绑定到RMI注册表。

3.1. 创建存根

首先生成远程对象的存根:

MessengerService server = new MessengerServiceImpl();
MessengerService stub = (MessengerService) UnicastRemoteObject
  .exportObject((MessengerService) server, 0);

UnicastRemoteObject.exportObject负责创建存根实现,存根通过底层RMI协议实现与服务器通信

参数说明:

  • 第一个参数:远程服务器对象
  • 第二个参数:导出端口(0表示动态选择端口)

❌ 注意:无端口号的exportObject()方法已废弃。

3.2. 创建注册表

注册表可本地创建或作为独立服务运行。这里采用本地创建:

Registry registry = LocateRegistry.createRegistry(1099);

✅ 关键点:

  • 默认端口1099(可在createRegistry中指定其他端口)
  • 服务器本地创建使用createRegistry
  • 独立服务场景需用getRegistry并传入主机名和端口

3.3. 绑定存根

将存根绑定到注册表(类似JNDI的命名服务):

registry.rebind("MessengerService", stub);

绑定后,任何能访问注册表的客户端都可使用该远程对象。

4. 创建客户端

客户端调用远程方法的步骤:

  1. 定位RMI注册表
  2. 通过唯一键查找远程对象存根
  3. 调用远程方法
Registry registry = LocateRegistry.getRegistry();
MessengerService server = (MessengerService) registry
  .lookup("MessengerService");
String responseMessage = server.sendMessage("Client Message");
String expectedMessage = "Server Message";
 
assertEquals(expectedMessage, responseMessage);

✅ 执行说明:

  • 因注册表在本地且使用默认端口1099,getRegistry无需参数
  • 若注册表在其他主机/端口,需传入相应参数
  • 获取存根后即可像本地对象一样调用方法

5. 总结

本文简要介绍了Java RMI的基础用法,展示了其作为客户端-服务器应用框架的核心能力。后续将深入探讨RMI的更多高级特性。

完整源码请参考:GitHub仓库


原始标题:Getting Started with Java RMI