文章目錄
- Java RMI
-
- 背景
- 基本原理
- 示例
-
- 服務端提供遠端調用的接口
- 服務端實作遠端接口
- 注冊中心
- 用戶端進行遠端調用
- 驗證
- 其他
- 官方文檔
Java RMI
背景
當不同JVM之間需要互相調用的時候,如何讓JVMA中調用JVMB中的方法像在本地一樣,這就出現了RMI-Remote Method Invoke
不同的JVM既可以指同一機器上的不同的JVM,也可以值不同機器上的JVM
基本原理
至于什麼存根、骨架這些,我覺得很難讓人記住并且這兩個詞也不容易望文生義,是以這裡借助目前流行的微服務的概念說一下。
如果對微服務有所了解的,RMI的調用過程其實和它很類似。
- 需要有一個注冊中心-RMI Registry。這裡面儲存着提供遠端服務的名字和具體的實作類
- 服務端需要提供能夠進行遠端調用的接口
- 服務端同時需要對上述接口進行實作
- 用戶端通過在RMI Registry中查找所需要的服務的名字,獲得其執行個體,進行遠端調用
如果真的想要了解其中的各種細節,強烈推薦閱讀Head First 設計模式一書中的代理模式章節,裡面生動詳細介紹了RMI的基本原理和細節
示例
服務端提供遠端調用的接口
- 繼承Remote接口
- 提供遠端服務的方法需要抛出 RemoteException
public interface RmiServerInterface extends Remote {
/**
* 所有提供RMI的方法,都要抛出RemoteException,否則會報
* Exception "remote object implements illegal remote interface"?
* 錯誤
* @return
* @throws RemoteException
*/
String sayHello() throws RemoteException;
}
服務端實作遠端接口
- 繼承UnicastRemoteObject
- 無參構造方法抛出RemoteException
public class RmiInterfaceImpl extends UnicastRemoteObject implements RmiServerInterface{
public RmiInterfaceImpl() throws RemoteException{
}
@Override
public String sayHello() {
return "hello, I'm Remote JVM Server";
}
}
注冊中心
public class Server {
public static void main(String[] args) throws RemoteException {
// 啟動注冊中心
Registry registry = LocateRegistry.createRegistry(2001);
try {
// 綁定服務
registry.bind("hello", new RmiInterfaceImpl());
System.err.println("Server ready");
} catch (AlreadyBoundException e) {
System.out.println("Server bind fail" + e.getMessage());
}
}
}
用戶端進行遠端調用
- 直接在RMI Registry中進行查找
public class RmiClient {
public static void main(String[] args) {
try {
// 查找名字必須為在注冊中心注冊的名字
RmiServerInterface hello = (RmiServerInterface) Naming.lookup("rmi://localhost:2001/hello");
System.out.println("接收到伺服器端的接口的傳回資訊是: " + hello.sayHello() +" "+ hello.getClass().getName());
} catch (RemoteException | NotBoundException | MalformedURLException e) {
System.out.println("Connect Server fail"+ e.getMessage());
}
}
}
驗證
- 啟動RMI Registry
- 啟動用戶端,觀察列印資訊,可以發現用戶端拿到的類其實是一個代理類
其他
- 如果服務端傳回的是一個類,那麼該類必須實作序列化接口,因為設計網絡傳輸、IO。是以必須實作序列化接口
- 代碼倉庫
- 由RMI可以想到RPC,那麼二者之間的關系如何呢?個人認為,RMI屬于RPC的子集,RMI是RPC針對Java語言以及對象特性的定制化開發,使得Java開發者非常友善的在不同的JVM之間進行調用
官方文檔
說明:按照官方文檔進行編碼,總是在設定codebase那裡有問題
- Java RMI文檔
- RMI關于動态下載下傳和codebase
- RMI常見問題