RMI(Remote Method Invocation)應用程序通常由兩個獨立程序構成:服務器程序與客戶機程序。服務器負責創建多個遠程對象並將其註冊供查找,隨後等待客戶機調用;客戶機則獲取遠程對象引用並調用其方法。RMI 為雙方通訊與信息傳遞提供了透明機制,這類應用被稱為分布式對象應用程序。
rmiregistry 註冊,或在常規操作中傳遞/返回引用。在 Java 分布式對象模型中,Remote Object 指其方法可從其他 Java 虛擬機(可能位於不同主機)調用的對象。此類對象由一個或多個 Remote Interface(聲明遠程方法的 Java 接口)描述。遠程方法調用 (RMI) 即調用遠程對象上遠程接口方法的動作,其語法與本地調用完全相同。
instanceof 檢測遠程對象支持的接口。java.lang.Object 某些方法語義專門針對遠程對象調整。RemoteException)。所有遠程接口必須直接或間接擴展 java.rmi.Remote。它是一個不包含方法的標記接口:
public interface Remote
遠程方法聲明要求:
throws 子句必須包含 java.rmi.RemoteException 或其超類(如 IOException、Exception)。public interface BankAccount extends java.rmi.Remote {
public void deposit(float amount) throws java.rmi.RemoteException;
public void withdraw(float amount) throws OverdrawnException, java.rmi.RemoteException;
public float getBalance() throws java.rmi.RemoteException;
}
public interface Alpha {
public final String okay = "constants are okay too";
public Object foo(Object obj) throws java.rmi.RemoteException;
public void bar() throws java.io.IOException;
public int baz() throws java.lang.Exception;
}
public interface Beta extends Alpha, java.rmi.Remote {
public void ping() throws java.rmi.RemoteException;
}
java.rmi.RemoteException 是 RMI 運行時拋出的異常超類,屬於已檢查異常(非 RuntimeException),調用者必須處理。常見失敗原因:
hashCode、equals、toString 的遠程語義。實現類通常擴展 UnicastRemoteObject 以繼承遠程行為,可實現多個遠程接口,也可定義僅本地可用的方法。構造函數需拋出 RemoteException。
package mypackage;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class BankAccountImpl extends UnicastRemoteObject implements BankAccount {
private float balance = 0.0f;
public BankAccountImpl(float initialBalance) throws RemoteException {
balance = initialBalance;
}
public void deposit(float amount) throws RemoteException { /* ... */ }
public void withdraw(float amount) throws OverdrawnException, RemoteException { /* ... */ }
public float getBalance() throws RemoteException { /* ... */ }
}
參數/返回值可為任意可序列化 Java 對象:基本類型、遠程對象、實現 Serializable 的非遠程對象。本地不可用的類可通過 RMI 動態下載。
| 對象類型 | 傳遞方式 | 說明 |
|---|---|---|
| 非遠程對象 | 按值傳遞(序列化複製) | 調用前複製內容;返回時在調用端創建新對象 |
| 遠程對象 | 按引用傳遞(傳遞 stub) | 僅傳遞實現遠程接口的 stub |
單次遠程調用中,若兩個引用指向發送端同一對象,接收端將指向同一副本。RMI 通過單一 ObjectOutputStream 寫入參數保證此特性。
對象跨 JVM 傳輸時,RMI 在調用流中用 codebase URL 註解類描述符,接收端可由此下載類定義。ObjectOutputStream 子類覆蓋 replaceObject(遠程對象替換為 stub)與 annotateClass(註解 codebase)。
RMI 提供基於 URL 的簡單引導命名服務。java.rmi.Naming 類提供 bind、rebind、unbind、list 等方法,操作特定主機/端口上的名字-對象綁定。客戶機通過 JNDI 或 Naming 查找獲取遠程引用,隨後發起調用。