首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

十分鐘上手 Java RMI:遠程方法調用完整入門範例

     編輯:Java 相關知識

Java RMI (Remote Method Invocation) 是 Java 原生的分布式物件調用機制,通過 Stub/Skeleton 代理實現跨 JVM 透明方法呼叫。雖然微服務時代多用 REST/gRPC,但 RMI 仍在傳統 Java EE 系統、內部服務調用、JMX 管理中廣泛使用。本文提供最精簡的三類別完整範例,涵蓋介面定義、服務端啟動、客戶端調用、rmic 編譯、rmiregistry 註冊表啟動全流程。

架構圖解

Client JVM                    Server JVM
+----------------+            +----------------+
|  Client Code   |            |  Impl Object   |
|  (Stub)  ─────→|  JRMP/RMI  |  (Skeleton)    |
+----------------+   Protocol +----------------+
        ↑                        ↑
   Naming.lookup()          Naming.rebind()
        ↑                        ↑
   +----------------+      +----------------+
   |  RMI Registry  |◀─────|  rmiregistry   |
   |  (Port 1099)   |      |  (獨立進程)     |
   +----------------+      +----------------+

三大核心類別

1. 遠程介面 (必須 extends Remote、方法拋 RemoteException)

// HelloIn.java
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface HelloIn extends Remote {
    String sayHello() throws RemoteException;
}

2. 服務端實作 (extends UnicastRemoteObject)


// HelloImpl.java
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.Naming;

public class HelloImpl extends UnicastRemoteObject implements HelloIn {

    protected HelloImpl() throws RemoteException {
        super(); // 匯出遠程物件,監聽匿名埠
    }

    @Override
    public String sayHello() throws RemoteException {
        return "Hello, RMI World! " + new java.util.Date();
    }

    public static void main(String[] args) {
        // System.setSecurityManager(new SecurityManager()); // JDK 8+ 通常不需
        try {
            HelloImpl obj = new HelloImpl();
            // 綁定到註冊表: rmi://host:port/name
            Naming.rebind("rmi://localhost:1099/HelloService", obj);
            System.out.println("RMI Server ready... (bound as HelloService)");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3. 客戶端調用


// HelloClient.java
import java.rmi.Naming;

public class HelloClient {
    public static void main(String[] args) {
        try {
            // 從註冊表查找遠程介面代理
            HelloIn service = (HelloIn) Naming.lookup("rmi://localhost:1099/HelloService");
            
            for (int i = 0; i < 5; i++) {
                System.out.println("Call " + i + ": " + service.sayHello());
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

關鍵步驟:編譯與啟動順序 (務必遵循)

  1. 編譯所有 .java:javac HelloIn.java HelloImpl.java HelloClient.java
  2. 生成 Stub/Skeleton (JDK 8 仍需):rmic HelloImpl
    產生 HelloImpl_Stub.class (客戶端代理) 與 HelloImpl_Skel.class (伺服端骨架,JDK 1.2+ 不再使用但仍生成)。類路徑必須包含遠程介面。
  3. 啟動 RMI 註冊表 (獨立終端機):rmiregistry
    預設端口 1099。注意:rmiregistry 的 classpath 不需 包含應用類別 (JDK 1.2+ 支援動態類下載),但若使用自定義類載入器需注意 java.rmi.server.codebase。
  4. 啟動服務端:java HelloImpl
    控制台顯示 RMI Server ready...
  5. 啟動客戶端:java HelloClient
    輸出 5 次問候訊息,證明遠程調用成功。

常見坑與解決方案

錯誤現象原因解決
ConnectException: Connection refusedrmiregistry 未啟動或端口錯誤先啟動 rmiregistry,確認端口 1099 未被佔用
ClassNotFoundException: HelloImpl_Stub未執行 rmic 或 classpath 缺少 Stub執行 rmic HelloImpl,確保 Stub 與介面同目錄
UnmarshalException: Class not found客戶端缺少遠程介面類別客戶端 classpath 包含 HelloIn.class
AccessException: Registry.Registry.rebind disallowedSecurityManager 禁止遠程綁定啟動參數 -Djava.security.policy=server.policy,策略檔授權 permission java.net.SocketPermission "*", "accept,connect,listen,resolve"
跨機器調用失敗IP/主機名解析、防火牆、codebase服務端啟動加 -Djava.rmi.server.hostname=實際IP;防火牆開放 1099 + 匿名埠範圍;若用動態下載需配置 java.rmi.server.codebase=https://host:port/classes/

進階主題速覽

  • 動態類下載:客戶端無 Stub 類時自動從 codebase URL 下載,需 HTTP 伺服器托管 .class 檔。
  • RMI over SSL:自定義 RMIClientSocketFactory/RMIServerSocketFactory 使用 SSLSocket。
  • 激活機制:rmid (Activation Daemon) 支援服務按需啟動、持久化狀態。
  • JMX 整合:JMXConnectorServer 底層即 RMI,service:jmx:rmi:///jndi/rmi://host:port/jmxrmi。

總結

RMI 以「介面導向、Stub 代理、註冊表發現」三大支柱,提供了純 Java 的分布式調用能力。掌握 rmic、rmiregistry、Naming 三大工具鏈與常見網路/安全配置坑,即可快速建立可用的 RMI 服務。現代架構下,RMI 更多作為內部管理平面 (JMX, Spring RMI Exporter) 或舊系統整合橋樑,新業務開發優先考慮 REST/gRPC/Dubbo 等跨語言、可觀測性更強的框架。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved