K:java中的RMI(Remote Method Invocation)

来源:https://www.cnblogs.com/MyStringIsNotNull/archive/2018/01/10/8261137.html
-Advertisement-
Play Games

相關介紹:  RMI全稱是Remote Method Invocation,即遠程方法調用。它是一種電腦之間利用遠程對象互相調用,從而實現雙方通訊的一種通訊機制。使用這種機制,某一臺電腦(虛擬機)上的對象可以調用另外一臺電腦(虛擬機)上的對象來獲取遠程數據。RMI是Enterpris ...


相關介紹:

 RMI全稱是Remote Method Invocation,即遠程方法調用。它是一種電腦之間利用遠程對象互相調用,從而實現雙方通訊的一種通訊機制。使用這種機制,某一臺電腦(虛擬機)上的對象可以調用另外一臺電腦(虛擬機)上的對象來獲取遠程數據。RMI是Enterprise JavaBeans的支柱,是建立分散式Java應用程式的方便途徑。在過去,TCP/IP套接字通訊是遠程通訊的主要手段,但此開發方式沒有使用面向對象的方式實現開發,在開發一個如此的通訊機制時往往令程式員感覺到乏味,對此RPC(Remote Procedure Call)應運而生,它使程式員更容易地調用遠程程式,但在面對複雜的信息傳訊時,RPC依然未能很好的支持,而且RPC未能做到面向對象調用的開發模式。針對RPC服務遺留的問題,RMI出現在世人面前,它被設計成一種面向對象的通訊方式,允許程式員使用遠程對象來實現通信,並且支持多線程的服務。

要想實現基於RMI的應用程式,需要實現如下四個類:

  1. 遠程對象介面: 這個介面中包含了所有遠程方法的聲明。在實際使用中,客戶端只需要知道這個介面的存在,並不關心這個介面是如何實現的。它擴展了java.rmi.Remote介面,定義了遠程對象執行的輸出方法。由於在通過網路調用遠程方法的過程中,有很多意想不到的問題可能會引發錯誤,為此,該介面中的每個方法都必須定義為拋出一個java.rmi.RemoteException異常,它是許多更專門的RMI異常類的父類。

  2. 遠程對象介面實現: 這是遠程對象介面的具體實現。它包含了實現遠程介面的具體代碼,可以在這些遠程方法的實現代碼中加入一些輸出語句(或者log4j),以測試其被調用的情況。遠程對象介面的實現類必須繼承自java.rmi.server.UnicastRemoteObject類。它代表了遠程對象或者伺服器對象。與聲明遠程方法來拋出RemoteException對象不同,該遠程對象不需要做任何專門的事情來允許它的方法被遠程調用。UnicastRemoteObject和RMI其餘的基本結構將自動進行處理。

  3. RMI伺服器端: RMI伺服器端生成遠程對象的一個實例,並用一個專用的URL對該對象進行註冊。在註冊時,首先要提供遠程對象所在伺服器的地址,同時需要對遠程對象進行標識,也就是給遠程對象一個名字。這個對象的名字在伺服器端和客戶端必須一致,這樣客戶端才能找到伺服器端的遠程對象。
    伺服器地址(serverAddress)+遠程對象名字(objectName)構成了RMI的註冊URL。

    其具體形式為:
    rmi://serverAddress:port/objectName
    埠號可以自己定義,預設埠是1099。如果使用預設埠,在URL裡面可以不用給出。下麵是一個URL的例子:
    rmi://192.168.1.123:2222/RemoteMethod

  4. RMI客戶端: RMI客戶端在遠程RMI伺服器端上查找服務對象,並將它轉換成本地介面類型,然後像對待一個本地對象一樣使用它。

 除了上述介紹的4個RMI相關的類之外,還需要有一個相關的安全策略文件,如java.policy。由於Java內置的安全策略對遠程方法調用有一定的限制,所以我們必須編寫一個安全策略文件(這是一個文本文件,文件名可以隨便起)。在啟動伺服器端時把策略文件載入到虛擬機中,這樣伺服器端才能正常運行。

一個簡單的例子:

 以下相關的代碼用於演示一個基於RMI的例子,客戶端傳入相關的參數,調用伺服器端對象的相關方法用來實現在客戶端輸出一段文字。

遠程對象介面:

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

/**
 * 用於演示遠程方法調用的實例
 * @author 學徒
 *此處定義了一個遠程方法調用的介面
 *
 */
public interface RMethod extends  Remote//該介面需要實現Remote介面
{
    public abstract String sayHello(String name) throws RemoteException;//Remote介面下的所有遠程調用的方法都必須拋出RemoteException異常
}

遠程對象介面實現:


import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

/**
 * 遠程對象介面的具體實現對象
 * @author 學徒
 *該實現對象必須繼承UnicastRemoteObject類,且實現定義的遠程對象的介面
 *
 *
 */
public class RMethodImpl extends UnicastRemoteObject implements RMethod
{
    private static final long serialVersionUID = 1L;

    protected RMethodImpl() throws RemoteException
    {
        super();
    }

    @Override
    public synchronized String sayHello(String name) throws RemoteException
    {
        System.out.println("Client-" + name + ": invoking \" sayHello \"");//以上的執行會發生在伺服器端
        return "Hello " + name + "\n\t this is a message from Remote Method";//該return的結果會返回給客戶端
    }
    
}

配置信息文件類:

/**
 * 該介面用於實現伺服器端和客戶端的共同配置,當遠程調用的某些信息發生改變時,只需要修改該介面的信息,而不需要去更改
 * 代碼
 * @author 學徒
 *
 *由於伺服器端需要註冊遠程對象調用的實例的URL,而且其格式為
 *rmi://serverAddress:port/objectName
 *
 *為此在下麵配置相關的信息
 */
public interface Config
{
    //對象實例的名字
    String OBJECT_NAME = "RemoteMethod";
    //對象伺服器的IP地址
    String SERVER_IP = "192.168.199.241";
    //對象伺服器進行監聽的埠號
    int PORT = 1234;
}

RMI伺服器端:


import java.rmi.RMISecurityManager;
import java.rmi.registry.LocateRegistry;

/**
 * 遠程對象調用的伺服器,該伺服器的作用是創建遠程對象實現的實例,並按照公用配置文件制定的對象名將這個實例註冊到伺服器端上。
 * 當註冊成功之後,伺服器端程式就處於阻塞狀態,等待客戶端的遠程對象訪問請求。
 * 
 * @author 學徒
 * 
 */
public class Server
{
    public static void main(String[] args)
    {
        new Server();
    }

    public Server()
    {
        if (null == System.getSecurityManager())
        {
            System.setSecurityManager(new RMISecurityManager());
        }
        try
        {
            try
            {
                //用於註冊遠程對象調用的監聽埠
                LocateRegistry.createRegistry(Config.PORT);
            }
            catch (java.rmi.server.ExportException ex)
            {
                System.out.println("Register the port failed:\n"+ ex.getMessage());
            }
            RMethod rm = new RMethodImpl();
            String objAddr = "rmi://" + Config.SERVER_IP + ":" + Config.PORT+ "/" + Config.OBJECT_NAME;
            //用於將該URL綁定到該對象實例上
            java.rmi.Naming.rebind(objAddr, rm);
            System.out.println("Server is running...");
        }
        catch (Exception e)
        {
            System.out.println("Server startup failed!");
            e.printStackTrace();
        }
    }
}

RMI客戶端:

/**
 * 在客戶端,其需要有和伺服器端同樣的兩個文件,一個是Config配置文件,因為其定義了RMI的配置信息,一個是
 * Remote介面類,該類在客戶端可以通過遠程方法調用的方式生成一個使用的實例。 該類用於實現遠程對象調用的客戶端程式
 * 客戶端通過調用伺服器端提供的遠程方法,來實現與伺服器的通信。這樣就不需要考慮具體的通信細節。
 * 只要像使用本地方法一樣調用伺服器端的遠程方法,完成需要的功能。 要調用遠程方法,客戶端必須先構造一個RMI
 * URL來找到遠程對象(註意在客戶端我們只使用遠程對象介面), 然後通過遠程對象來調用遠程方法。
 * 
 * @author 學徒
 * 
 */
public class Client
{
    private String name;
    private String hostURL;
    private String obj;

    public Client(String name)
    {
        this.name = name;
        hostURL = "rmi://" + Config.SERVER_IP + ":" + Config.PORT + "/";
        this.obj = Config.OBJECT_NAME;
    }

    public void callRMethod()
    {
        try
        {
            RMethod rm = (RMethod) java.rmi.Naming.lookup(hostURL + obj);
            String result = rm.sayHello(name);
            System.out.println(result);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args)
    {
        Client c1 = new Client("Monica");
        c1.callRMethod();
        Client c2 = new Client("Joy");
        c2.callRMethod();
        Client c3 = new Client("Ross");
        c3.callRMethod();
        Client c4 = new Client("Chandler");
        c4.callRMethod();
    }

}

安全策略文件:

grant {
    permission java.security.AllPermission;
};


ps:為方便說明該示例,文件的文件名取為java.policy

執行過程:

 編寫了相關的java類之後,按照如下的方式創建訪問過程:

命令行模式

編譯:

$ javac *.java

運行伺服器端:

$ rmic RMethodImpl

$ java -Djava.security.policy=java.policy Server

Server is running...//此處是伺服器端啟動後的輸出

運行客戶端:

$ java Client

Hello Monica

 this is a message from Remote Method

Hello Joy

 this is a message from Remote Method

Hello Ross

 this is a message from Remote Method

Hello Chandler

 this is a message from Remote Method

伺服器端對應的輸出為:

$ java -Djava.security.policy=java.policy Server

Server is running...

Client-Monica: invoking " sayHello "

Client-Joy: invoking " sayHello "

Client-Ross: invoking " sayHello "

Client-Chandler: invoking " sayHello "

從輸出結果中可以看出,遠程方法的調用將其相關的方法的執行放在了伺服器端,而客戶端只需要傳遞相關的參數,以及接收相應的結果即可

伺服器相關的文件:

伺服器端文件目錄

客戶端相關的文件:

客戶端文件目錄

回到目錄|·(工)·)

參考博文: 學習筆記:JAVA RMI遠程方法調用簡單實例

推薦文章:深入理解rmi原理。在看這篇文章前,先瞭解如下兩個概念:1. stub和Skeleton:這兩個的身份是一致的,都是作為代理的存在。客戶端的稱作Stub,服務端的稱作Skeleton。要做到對程式員屏蔽遠程方法調用的細節,這兩個代理是必不可少的,包括網路連接等細節。2. Registry:顧名思義,可以認為Registry是一個“註冊所”,提供了服務名到服務的映射。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 上篇文章--筆記19簡要介紹了成員內部類、局部內部類和匿名內部類,下麵對成員內部類再補充一些內容。 主要有以下6點: 1.成員內部類不可以有靜態成員,成員變數為static final時除外 2.外部類不可以直接訪問成員內部類的成員變數或調用成員內部類的成員方法 3.成員內部類可以無限制的訪問外部類 ...
  • 1.單位元組字元串反轉 php提供了用於字元串反轉的函數strrev() 2.對於包含中文的多位元組字元串需要用到mb_substr() 3.演算法實現 首位交換 ...
  • 一.列表 1.列表的定義 列表是一個有序的集合。 2.正向訪問列表中的元素 3.逆向訪問列表中的元素 3.切片取值 語句:列表名[下標1:下標2:步長3] 以步長3取出下標1到下標2(包括下標1不包括下標2)之間的元素。 students =['xiaoMing', 'LiLei', 'HanMei ...
  • Flask框架中的信號基於blinker,其主要就是讓開發者可是在flask請求過程中定製一些用戶行為 1. 內置信號 源碼示例 class Flask(_PackageBoundObject): def full_dispatch_request(self): self.try_trigger_b ...
  • 委托構造 C++11 引入了委托構造的概念,可以在一個構造函數調用另一個構造函數,從而達到簡化代碼的目的: class Base {public:int value1;int value2;Base() { value1 = 1; } Base(int ... ...
  • svn安裝 ubuntu: apt-get install subversion centos: yum install subversion 版本庫的創建 svnadmin create /path/repos //版本的路徑以及名稱 版本庫創建後可跟參數 fsfs和dbd表示數據保存類型. sv ...
  • 方法引用(Method Reference) 上一篇中記錄了Lambda表達式,其可以創建匿名方法。當Lambda表達式只是調用一個存在的方法時,可以採用方法引用(JDK8具有的特性)。如下: 假設需要對一組人員按年齡進行排序,可以採用下邊的方式,將人員數組與實現的比較器,傳遞給Array.sort ...
  • 閑來無事,練習了一下Java基礎中的迴圈語句。練習迴圈語句,當然少不了,用*列印出來三角形、空心三角形、菱形等這樣的幾何圖形。 粗心大意,失誤兩次: 一、三角形 遇到一些小問題: 二、金字塔 由於三角形和金字塔的代碼差不多,只有少部分更改,圖也可以看的很清楚。所以下麵只寫一部分代碼好啦。 代碼實例: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...