RMI (Remote Method Invocation) 是 Java 原生分散式物件機制,也是 EJB 底層支柱。本文以「遠端計算機服務」為例,完整演示 RMI 系統開發的七大步驟:介面定義、實作、Stub 生成、Server/Client 開發、Registry 啟動、安全策略、分散式執行驗證。
extends Remote)extends UnicastRemoteObject)
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Calculator extends Remote {
long add(long a, long b) throws RemoteException;
long sub(long a, long b) throws RemoteException;
long mul(long a, long b) throws RemoteException;
long div(long a, long b) throws RemoteException;
}
鐵律:介面 `public`、繼承 `Remote`、所有方法 `throws RemoteException`。
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
public class CalculatorImpl extends UnicastRemoteObject implements Calculator {
// 必須顯式建構子並拋出 RemoteException
public CalculatorImpl() throws RemoteException {
super(); // 啟動 RMI 連結、匯出物件
}
public long add(long a, long b) throws RemoteException { return a + b; }
public long sub(long a, long b) throws RemoteException { return a - b; }
public long mul(long a, long b) throws RemoteException { return a * b; }
public long div(long a, long b) throws RemoteException { return a / b; }
}
關鍵點:繼承 `UnicastRemoteObject` 表示單點 TCP 連線遠端物件。若不繼承,需手動呼叫 `UnicastRemoteObject.exportObject(this)`。
javac Calculator.java CalculatorImpl.java
rmic CalculatorImpl
產生:`CalculatorImpl_Stub.class` (Client 代理)、`CalculatorImpl_Skel.class` (Server 骨架,JDK 1.2+ 可選)。
import java.rmi.Naming;
import java.rmi.RemoteException;
public class CalculatorServer {
public CalculatorServer() {
try {
Calculator calc = new CalculatorImpl();
// 註冊到 Registry:rmi://host:port/name
Naming.rebind("rmi://localhost:1099/CalculatorService", calc);
System.out.println("CalculatorService bound in registry");
} catch (Exception e) {
System.out.println("Trouble: " + e);
e.printStackTrace();
}
}
public static void main(String[] args) {
new CalculatorServer();
}
}
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
public class CalculatorClient {
public static void main(String[] args) {
try {
// 從 Registry 查找遠端物件參考
Calculator calc = (Calculator) Naming.lookup("rmi://localhost/CalculatorService");
// 想像呼叫本地方法,實則跨 JVM 執行
System.out.println("4 - 3 = " + calc.sub(4, 3));
System.out.println("4 + 5 = " + calc.add(4, 5));
System.out.println("3 * 6 = " + calc.mul(3, 6));
System.out.println("9 / 3 = " + calc.div(9, 3));
} catch (MalformedURLException | RemoteException | NotBoundException e) {
e.printStackTrace();
} catch (ArithmeticException e) {
System.out.println("ArithmeticException: " + e.getMessage());
}
}
}
# 確保在類別檔案目錄下執行
rmiregistry
# 或指定埠
rmiregistry 4500
建立 `policy.txt`:
grant {
permission java.security.AllPermission "", "";
};
生產環境嚴禁使用 AllPermission,此處僅示範。
java -Djava.security.policy=policy.txt CalculatorServer
java CalculatorClient
4 - 3 = 1
4 + 5 = 9
3 * 6 = 18
9 / 3 = 3
| 組件 | 本機部署 | 跨機器部署 |
|---|---|---|
| Registry | localhost:1099 | Server IP:1099 (Server 機器啟動) |
| Server 註冊 | rmi://localhost:1099/name | rmi://server-ip:1099/name |
| Client 查找 | rmi://localhost/name | rmi://server-ip/name |
| Client 需檔案 | 所有 class | 介面 + Stub 類別 |
| Server 需檔案 | 所有 class | 實作 + Stub/Skeleton + 介面 |
避免手動複製 Stub/介面類別:
-Djava.rmi.server.codebase=https://server-ip:8000/RMI 以「介面驅動、Stub 代理、Registry 命名」三大支柱構建 Java 分散式系統。本文計算機服務範例完整覆蓋開發、編譯、Stub 生成、註冊、查找、呼叫、安全策略、跨機器部署全生命週期。掌握此流程,即掌握 Java 分散式程式設計的核心內功,也是理解 EJB、Jini、分散式 Spring Remoting 的基石。