天天看點

JavaRMI入門和使用Java RMI

文章目錄

  • Java RMI
    • 背景
    • 基本原理
    • 示例
      • 服務端提供遠端調用的接口
      • 服務端實作遠端接口
      • 注冊中心
      • 用戶端進行遠端調用
      • 驗證
    • 其他
    • 官方文檔

Java RMI

背景

當不同JVM之間需要互相調用的時候,如何讓JVMA中調用JVMB中的方法像在本地一樣,這就出現了RMI-Remote Method Invoke

不同的JVM既可以指同一機器上的不同的JVM,也可以值不同機器上的JVM

基本原理

至于什麼存根、骨架這些,我覺得很難讓人記住并且這兩個詞也不容易望文生義,是以這裡借助目前流行的微服務的概念說一下。

如果對微服務有所了解的,RMI的調用過程其實和它很類似。

  • 需要有一個注冊中心-RMI Registry。這裡面儲存着提供遠端服務的名字和具體的實作類
  • 服務端需要提供能夠進行遠端調用的接口
  • 服務端同時需要對上述接口進行實作
  • 用戶端通過在RMI Registry中查找所需要的服務的名字,獲得其執行個體,進行遠端調用

如果真的想要了解其中的各種細節,強烈推薦閱讀Head First 設計模式一書中的代理模式章節,裡面生動詳細介紹了RMI的基本原理和細節

示例

服務端提供遠端調用的接口

  1. 繼承Remote接口
  2. 提供遠端服務的方法需要抛出 RemoteException
public interface RmiServerInterface extends Remote {
    
    /**
     * 所有提供RMI的方法,都要抛出RemoteException,否則會報
     * Exception "remote object implements illegal remote interface"?
     * 錯誤
     * @return
     * @throws RemoteException
     */
    String sayHello() throws RemoteException;
}
           

服務端實作遠端接口

  1. 繼承UnicastRemoteObject
  2. 無參構造方法抛出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());
        }
    }
}
           

用戶端進行遠端調用

  1. 直接在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());
        }
    }
}
           

驗證

  1. 啟動RMI Registry
  2. 啟動用戶端,觀察列印資訊,可以發現用戶端拿到的類其實是一個代理類

其他

  1. 如果服務端傳回的是一個類,那麼該類必須實作序列化接口,因為設計網絡傳輸、IO。是以必須實作序列化接口
  2. 代碼倉庫
  3. 由RMI可以想到RPC,那麼二者之間的關系如何呢?個人認為,RMI屬于RPC的子集,RMI是RPC針對Java語言以及對象特性的定制化開發,使得Java開發者非常友善的在不同的JVM之間進行調用

官方文檔

說明:按照官方文檔進行編碼,總是在設定codebase那裡有問題

  • Java RMI文檔
  • RMI關于動态下載下傳和codebase
  • RMI常見問題