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

Java RMI 遠程方法調用完整教程:從原理到實戰的五步驟實作指南

     編輯:Java 相關知識

RMI (Remote Method Invocation) 是 Java 內建的分散式物件框架,讓跨 JVM 物件調用如同本地調用般透明。本文系統解析 RMI 核心機制、五步驟實作流程、關鍵類別、安全模型與完整代碼範例。

RMI 核心優勢

  • 物件級透明調用:語法與本地調用一致,屏蔽 Socket/TCP 細節
  • 完整物件傳遞:支援任意可序列化物件作為參數/返回值(含集合、自訂類別)
  • 可移動行為:程式碼可在客戶/伺服端動態下載執行
  • 內建安全:SecurityManager 保護惡意代碼執行
  • 面向對象設計:自然支援多層架構、領域模型分散式部署

核心類別與介面

五步驟建立 RMI 應用

步驟 1:定義遠端介面

package com.example.rmi;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface HelloService extends Remote {
    String sayHello(String name) throws RemoteException;
    int add(int a, int b) throws RemoteException;
}
  • 介面必須 public、繼承 Remote
  • 所有方法拋出 RemoteException
  • 參數/返回值必須可序列化或為遠端介面

步驟 2:實作遠端介面

package com.example.rmi;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class HelloServiceImpl extends UnicastRemoteObject implements HelloService {
    protected HelloServiceImpl() throws RemoteException { super(); }

    @Override
    public String sayHello(String name) throws RemoteException {
        return "Hello, " + name + "! Server time: " + new java.util.Date();
    }

    @Override
    public int add(int a, int b) throws RemoteException {
        return a + b;
    }
}
  • 繼承 UnicastRemoteObject 獲得遠端能力
  • 建構子必須拋出 RemoteException

步驟 3:生成 Stub/Skeleton (JDK 5+ 可略過)

rmic com.example.rmi.HelloServiceImpl

JDK 5+ 使用動態 Proxy 替代預生成 Stub,rmic 僅在需相容舊版客戶端時必要。

步驟 4:編寫伺服端啟動類

package com.example.rmi;

import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;

public class Server {
    public static void main(String[] args) {
        try {
            // 1. 建立並啟動 Registry (埠 1099)
            LocateRegistry.createRegistry(1099);
            
            // 2. 實例化遠端物件
            HelloService service = new HelloServiceImpl();
            
            // 3. 綁定名稱至 Registry
            Naming.rebind("rmi://localhost:1099/HelloService", service);
            
            System.out.println("RMI Server ready: rmi://localhost:1099/HelloService");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

步驟 5:編寫客戶端調用類

package com.example.rmi;

import java.rmi.Naming;

public class Client {
    public static void main(String[] args) {
        try {
            // 1. 從 Registry 查找遠端物件
            HelloService service = (HelloService) Naming.lookup("rmi://localhost:1099/HelloService");
            
            // 2. 像本地調用一樣呼叫遠端方法
            System.out.println(service.sayHello("RMI Learner"));
            System.out.println("10 + 20 = " + service.add(10, 20));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

執行順序與驗證

  1. 編譯所有類別:javac com/example/rmi/*.java
  2. 啟動伺服端:java com.example.rmi.Server
  3. 啟動客戶端:java com.example.rmi.Client
  4. 觀察客戶端輸出遠端方法執行結果

進階主題

安全管理器與代碼下載

// 伺服端啟動參數
java -Djava.security.policy=server.policy \
     -Djava.rmi.server.codebase=file:/path/to/classes/ \
     com.example.rmi.Server

server.policy 範例:

grant {
    permission java.security.AllPermission;
};

自定義 Socket 工廠(SSL/防火牆/連線池)

// 伺服端
LocateRegistry.createRegistry(1099, 
    new SslRMIClientSocketFactory(), 
    new SslRMIServerSocketFactory());

// 客戶端
Registry registry = LocateRegistry.getRegistry("host", 1099,
    new SslRMIClientSocketFactory());

RMI vs 現代替代方案

類別/介面套件角色
Remotejava.rmi標記介面,遠端物件必須實作
UnicastRemoteObjectjava.rmi.server遠端物件基類,提供單點連線實作
Namingjava.rmi註冊表查找/綁定:lookup/bind/rebind
Registryjava.rmi.registry名稱服務,預設埠 1099
RemoteExceptionjava.rmi所有遠端方法必須拋出的檢查型異常
維度RMIgRPCSpring Cloud OpenFeignDubbo
協定JRMP (Java 私有)HTTP/2 + ProtobufHTTP/JSONTCP + Hessian/Kryo
跨語言不支援支援支援支援
服務發現手動/Registry需外掛Eureka/Consul/Nacos內建註冊中心
負載均衡無Client-sideRibbon/Spring Cloud LB內建策略
適用場景純 Java 內部系統微服務、多語言Spring 生態微服務高效能 RPC、治理

常見問題排查

  1. ClassNotFoundException:codebase 路徑錯誤或類未部署
  2. ConnectException: Connection refused:Registry 未啟動、埠號錯誤、防火牆攔截
  3. UnmarshalException:序列化版本不一致(serialVersionUID)、類定義不同
  4. AccessException:SecurityManager 禁止綁定/查找,檢查 policy 檔案

RMI 作為 Java 分散式計算的基石,雖在微服務時代逐漸被跨語言 RPC 取代,但其「物件透明分散」的設計哲學、序列化機制、安全模型仍值得深入學習,為理解現代分散式框架奠定堅實基礎。

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