如何發佈RMI服務;Java實現簡易RPC框架

1 、RMI是什麼

在 Java 世界裏,有一種技術可以實現“跨虛擬機”的調用,它就是 RMI(Remote Method Invocation,遠程方法調用)。例如,服務A 在 JVM1 中運行,服務B 在 JVM2 中運行,服務A 與 服務B 可相互進行遠程調用,就像調用本地方法一樣,這就是 RMI。在分佈式系統中,我們使用 RMI 技術可輕鬆將服務提供者(Service Provider)與服務消費者(Service Consumer)進行分離,充分體現組件之間的弱耦合,系統架構更易於擴展。

2、RMI遠程方法調用原理

在這裏插入圖片描述
方法調用從客戶對象經佔位程序(Stub)、遠程引用層(Remote Reference Layer)和傳輸層(Transport Layer)向下,傳遞給主機,然後再次經傳 輸層,向上穿過遠程調用層和骨幹網(Skeleton),到達服務器對象。 佔位程序扮演着遠程服務器對象的代理的角色,使該對象可被客戶激活。 遠程引用層處理語義、管理單一或多重對象的通信,決定調用是應發往一個服務器還是多個。傳輸層管理實際的連接,並且追蹤可以接受方法調用的遠程對象。服務器端的骨幹網完成對服務器對象實際的方法調用,並獲取返回值。返回值向下經遠程引用層、服務器端的傳輸層傳遞迴客戶端,再向上經傳輸層和遠程調用層返回。最後,佔位程序獲得返回值。
要完成以上步驟需要有以下幾個步驟:
(1)、 生成一個遠程接口
(2)、 實現遠程對象(服務器端程序)
(3)、 生成佔位程序和骨幹網(服務器端程序)
(4)、 編寫服務器程序
(5)、 編寫客戶程序
(6)、 註冊遠程對象
(7)、 啓動遠程對象

3、發佈RMI服務

發佈的一個RMI服務,我們需做三件事情
1、定義一個RMI接口
2、編寫RMI接口的實現類
3、通過JNDI發佈RMI服務

3.1 定義一個RMI接口
RMI接口實際上還是一個普通的Java接口,只是RMI接口必須繼承java.rmi.Remote,此外,RMI接口內的每個方法必須聲明拋出一個java.rmi.RemoteException異常,就像下面這樣

package org.bird.rmi2;  
  
import java.rmi.Remote;  
import java.rmi.RemoteException;  
  
public interface CalculateService extends Remote {  
  
    public int add(int a, int b) throws RemoteException;  
}  

繼承了Remote接口,實際上就是讓JVM知道該接口需要用於遠程調用的,拋出RemoteException是爲了讓調用RMI服務的程序捕獲這個異常根據相應異常情況進行後續處理,畢竟遠程調用過程中,什麼奇怪的事情都有可能發生(如:斷網)。需要說明的是,RemoteException是一個”受檢異常“,在調用的時候必須使用try…catch…自行處理。

3.2 編寫RMI接口的實現類
實現上面的CalculateService比較簡單,但是需要注意的是,我們必須讓實現類繼承java.rmi.server.UnicastRemoteObject類,此外,必須提供一個構造器,並且構造器必須拋出java.rmi.RemoteException異常。所以說,我們使用JVM提供的這一套RMI框架,就必須按照這些要求來實現,否則是無法成功發佈RMI服務的。就像下面這樣

package org.bird.rmi2;  
  
import java.rmi.RemoteException;  
import java.rmi.server.UnicastRemoteObject;  
  
public class CalculateServiceImpl extends UnicastRemoteObject implements  
        CalculateService {  
    /** 
     *  
     */  
    private static final long serialVersionUID = 1L;  
      
      
    protected CalculateServiceImpl() throws RemoteException {  
        super();  
    }  
  
    public int add(int a, int b) throws RemoteException {  
        return a + b;  
    }  
  
}  

爲了滿足RMI框架的要求,我們確實需要做很多額外的工作(繼承了UnicastRemoteObject類,拋出RemoteException異常)。我們可以通過JVM提供的JNDI(Java Naming and Directory Interface,Java 命名與目錄接口)這個API方便的發佈RMI服務。

3.3通過JNDI發佈RMI服務
發佈RMI服務,我們需要告訴JNDI三個基本信息:1.域名或IP地址(host)、2.端口號(port)、3、服務名(service),它們構成了RMI協議的URL

rmi://<host>:<port>/<service> 

如果我們是在本地發佈RMI服務,那麼host就是localhost。此外RMI默認的端口是1099,我們也可以自行設置port的值(可以與其他端口衝突)。service是基於host與port下唯一的服務名稱。需要保證RMI地址的唯一性。對於我們示例,RMI地址爲:

rmi://localhost:1099/calculate  

我們提供一個main()方法來發布示例RMI服務,就像下面

package org.bird.rmi2;  
  
import java.net.MalformedURLException;  
import java.rmi.AlreadyBoundException;  
import java.rmi.Naming;  
import java.rmi.RemoteException;  
import java.rmi.registry.LocateRegistry;  
  
public class RMIServer {  
  
    /** 
     * @param args 
     * @throws RemoteException  
     * @throws AlreadyBoundException  
     * @throws MalformedURLException  
     */  
    public static void main(String[] args) throws RemoteException, MalformedURLException, AlreadyBoundException {  
        int port = 1099;  
        LocateRegistry.createRegistry(port);  
        String url = "rmi://localhost:" + port + "/calculate";  
        Naming.bind(url, new CalculateServiceImpl());  
    }  
  
}  

我們通過LocateRegistry.createRegistry()方法在JNDI中創建一個註冊表,只需提供一個RMI端口即可。通過Naming.bind()方法綁定RMI地址與服務的實現類。運行這個main()方法,RMI服務就會自動發佈,剩下的事情就是寫一個RMI客戶端來調用剛發佈的RMI服務。

4、調用RMI服務

同樣,我們也利用一個main()方法來調用RMI服務。調用服務我們只需要知道兩個信息:1.RMI請求地址、2.RMI接口(一定不要使用RMI的實現類,否則就是本地調用)。少量代碼就能調用剛纔發佈的RMI服務了,就像下面這樣

package org.bird.rmi2;  
  
import java.net.MalformedURLException;  
import java.rmi.Naming;  
import java.rmi.NotBoundException;  
import java.rmi.RemoteException;  
  
public class RMIClient {  
  
    /** 
     * @param args 
     * @throws NotBoundException  
     * @throws RemoteException  
     * @throws MalformedURLException  
     */  
    public static void main(String[] args) throws MalformedURLException, RemoteException, NotBoundException {  
        String url = "rmi://localhost:1099/calculate";  
        CalculateService calculate = (CalculateService) Naming.lookup(url);  
        int sum = calculate.add(100, 400);  
        System.out.println(sum);  
    }  
  
}  

當我們運行以上的main()方法,在控制檯看到”500“輸出,表明RMI調用成功。
在這裏插入圖片描述

本文轉自:https://www.iteye.com/blog/liangjf85-163-com-2162928
Java實現簡易RPC框架參考一:Java實現簡易RPC框架(一)
二:Java實現簡易RPC框架(二)
三:Java實現簡易RPC框架(三)

發佈了17 篇原創文章 · 獲贊 3 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章