java rmi 使用教程及原理

什麼是rmi

RMI,是Remote Method Invocation(遠程方法調用)的縮寫,即在一個JVM中java程序調用在另一個遠程JVM中運行的java程序,這個遠程JVM既可以在同一臺實體機上,也可以在不同的實體機上,兩者之間通過網絡進行通信。java RMI封裝了遠程調用的實現細節,進行簡單的配置之後,就可以如同調用本地方法一樣,比較透明地調用遠端方法。

RMI包括以下三個部分:

  • Registry: 提供服務註冊與服務獲取。即Server端向Registry註冊服務,比如地址、端口等一些信息,Client端從Registry獲取遠程對象的一些信息,如地址、端口等,然後進行遠程調用。
  • Server: 遠程方法的提供者,並向Registry註冊自身提供的服務
  • Client: 遠程方法的消費者,從Registry獲取遠程方法的相關信息並且調用

jdk中java.rmi包簡介

Remote

一個interface,這個interface中沒有聲明任何方法。只有定義在“remote interface",即繼承了Remote的接口中的方法,纔可以被遠程調用。

RemoteException

RemoteException是所有在遠程調用中所拋出異常的超類,所有能夠被遠程調用的方法聲明,都需要拋出此異常

Naming

提供向註冊中心保存遠程對象引用或者從註冊中心獲取遠程對象引用的方法。這個類中的方法都是靜態方法,每一個方法都包含了一個類型爲String的name參數, 這個參數是URL格式,形如://host:port/name

Registry

一個interface, 其功能和Naming類似,每個方法都有一個String類型的name參數,但是這個name不是URL格式,是遠程對象的一個命名。Registry的實例可以通過方法LocateRegistry.getRegistry()獲得

LocateRegistry

用於獲取到註冊中心的一個連接,這個連接可以用於獲取一個遠程對象的引用。也可以創建一個註冊中心。

RemoteObject

重新覆寫了Object對象中的equals,hashCode,toString方法,從而可以用於遠程調用

UnicastRemoteObject

用於RMI Server中導出一個遠程對象並獲得一個stub。這個stub封裝了底層細節,用於和遠程對象進行通信。

Unreferenced

一個interface, 聲明瞭方法:void unreferenced()如果一個遠程隊形實現了此接口,則這個遠程對象在沒有任何客戶端引用的時候,這個方法會被調用。

rmi使用

在這一節,我們將從頭開始寫一個簡單的RMI示例,實現輸入名字,返回“Hello, XXX"的工程。創建一個完整的遠程調用,我們分爲以下幾步:

  1. 定義一個遠程接口,這個接口需要繼承Remote,並且接口中的每一個方法都需要拋出RemoteException異常
  2. 開發遠程接口的實現類
  3. Registry的創建
  4. RMI Server的創建
  5. RMI Client的創建

定義一個遠程接口

package com.luckyqiao.rmi;

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

public interface RemoteHello extends Remote {
    String sayHello(String name) throws RemoteException;
}

開發遠程接口的實現類

package com.luckyqiao.rmi;

import java.rmi.RemoteException;

public class RemoteHelloImpl  implements RemoteHello {
    public String sayHello(String name) throws RemoteException {
        return String.format("Hello, %s!", name);
    }
}

Registry 的創建

package com.luckyqiao.rmi;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.util.concurrent.CountDownLatch;

public class RegistryServer {
    public static void main(String[] args) throws InterruptedException{
        try {
            LocateRegistry.createRegistry(8000); //Registry使用8000端口
        } catch (RemoteException e) {
            e.printStackTrace();
        }

        CountDownLatch latch=new CountDownLatch(1);
        latch.await();  //掛起主線程,否則應用會退出
    }
}

RMI Server 的創建

package com.luckyqiao.rmi;

import java.io.IOException;
import java.rmi.AlreadyBoundException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class RMIServer {

    public static void main(String[] args) {

        RemoteHello remoteHello = new RemoteHelloImpl();
        try {
            RemoteHello stub = (RemoteHello) UnicastRemoteObject.exportObject(remoteHello, 4000); //導出服務,使用4000端口
            Registry registry = LocateRegistry.getRegistry("127.0.0.1", 8000); //獲取Registry
            registry.bind("hello", stub); //使用名字hello,將服務註冊到Registry
        } catch (AlreadyBoundException | IOException e) {
            e.printStackTrace();
        }

    }
}

RMI Client的創建

package com.luckyqiao.study.rmi;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class RMIClient {
    public static void main(String[] args) {
        try {
            Registry registry = LocateRegistry.getRegistry("127.0.0.1", 8000);  //獲取註冊中心引用
            RemoteHello remoteHello = (RemoteHello) registry.lookup("hello"); //獲取RemoteHello服務
            System.out.println(remoteHello.sayHello("World"));  //調用遠程方法
        } catch (RemoteException | NotBoundException e) {
            e.printStackTrace();
        }
    }
}

原理

未完待續

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章