Java的RMI遠程方法調用實現和應用

來源:互聯網
上載者:User

標籤:傳輸   資料   命令   結果   序列化   vm虛擬機器   轉換   增加   form   

最近在學習Dubbo,RMI是很重要的底層機制,RMI(Remote Method Invocation)遠程方法調用是一種電腦之間利用遠程對象互相調用實現雙方通訊的一種通訊機制。使用這種機制,某一台電腦(即JVM虛擬機器)上的對象可以調用另外一台電腦上的對象來擷取遠端資料。

RMI的實現對建立分布式Java應用程式至關重要,是Java體系非常重要的底層技術。

1.RMI的概念和原理

RMI思路是在用戶端安裝一個代理(proxy),代理是位於用戶端虛擬機器中的一個對象,對於用戶端對象,看起來就像訪問的遠程對象一樣,用戶端代理會使用網路通訊協定與伺服器進行通訊。
同樣的服務端也會有一個代理對象來進行通訊的繁瑣工作。

在RMI中,用戶端的代理對象被稱為存根(Stub),存根位於用戶端機器上,它知道如何通過網路與伺服器聯絡。存根會將遠程方法所需的參數打包成一組位元組。對參數編碼的過程被稱為參數編組(parameter marshalling),參數編組的目的是將參數轉換成適合在虛擬機器之間進行傳遞的形式。在RMI協議中,對象時使用序列化機制進行編碼的。

總的來說,用戶端的存根方法構造了一個資訊塊,它由以下幾部分組成
被使用的遠程對象的標識符;
被調用的方法的描述;
編組後的參數;

然後,存根將此資訊發送給伺服器。在伺服器的一端,接收器對象執行以下動作:
定位要調用的遠程對象;
調用所需的方法,並傳遞用戶端提供的參數;
捕獲傳回值或調用產生的異常;
將傳回值編組,打包送回給用戶端存根;
用戶端存根對來自伺服器端的傳回值或異常進行反編組,其結果就成為了調用存根傳回值。

2.RMI體繫結構

樁/架構(Stub/Skeleton)層:用戶端的樁和伺服器端的架構;
遠端參照(remote reference)層:處理遠端參照行為
傳送層(transport):串連的建立和管理,以及遠程對象的跟蹤

3.RMI與代理模式

RMI的實現是典型的代理模式思想。

(1)代理模式的UML圖

代理模式為其他對象提供一種代理以控制對這個對象的訪問,把調用者與被調用者分離開,由代理負責傳遞資訊來完成調用。
比如你想買美版Iphone6s,朋友出國,幫你海淘帶回,整個過程就是代理模式,朋友作為代理,代你完成你想進行的操作。

代理模式能將代理對象與真正被調用的對象分離,在一定程度上降低了系統的耦合度;
在用戶端和目標對象之間起到一個中介作用,這樣可以起到保護目標對象的作用,代理對象也可以對目標對象調用之前進行其他動作。
代理模式在用戶端和目標對象增加一個代理對象,會造成請求處理速度變慢;同時也增加了系統的複雜度。

(2)代理模式在RMI這種的體現

遠程代理的內部機制是這樣的:

下面的RMI執行個體,其實就是一個代理模式的應用。

4.RMI的簡單一實例

RMI的開發步驟如下:
先建立遠程介面及聲明遠程方法,注意這是實現雙方通訊的介面,需要繼承Remote
開發一個類來實現遠程介面及遠程方法,值得注意的是實作類別需要繼承UnicastRemoteObject
通過javac命令編譯檔案,通過java -server 命令註冊服務,啟動遠程對象
最後用戶端尋找遠程對象,並調用遠程方法

(1)服務端遠程介面
建立遠程介面SearchService,介面必須繼承Remote類,每一個定義方法都要拋出RemoteException異常

import java.rmi.Remote;import java.rmi.RemoteException; public interface SearchService extends Remote {    public User findUser(String id) throws RemoteException;;}

(2)建立SearchServiceImpl實現遠程介面,注意此為遠程對象實作類別,需要繼承UnicastRemoteObject

import java.rmi.RemoteException;public class SearchServiceImpl implements SearchService{     /**     * 拋出RemoteException     * @throws RemoteException     */    public SearchServiceImpl() throws RemoteException {        super();        }         @Override    public User findUser(String id) throws RemoteException {        /**         * 類比尋找返回資料         */        User user=new User(id,"Tom","18歲");        return user;    } }

(3)為服務建立一個Model層,此對象需要遠程傳輸,所以必須實現implements Serializable序列化介面,也就是可以在client和server端進行傳輸的可序列化對象
建立User類,用於資料轉送:

public class User implements Serializable{     private static final long serialVersionUID = 1L;         private String id;    private String name;    private String age;         public User(String id,String name,String age){        this.id=id;        this.name=name;        this.age=age;    }         public String getId() {        return id;    }     public void setId(String id) {        this.id = id;    }     public String getName() {        return name;    }     public void setName(String name) {        this.name = name;    }     public String getAge() {        return age;    }     public void setAge(String age) {        this.age = age;    }         public String toString(){        StringBuffer sb=new StringBuffer();        sb.append("~使用者id-"+id);        sb.append("~使用者姓名-"+id);        sb.append("~使用者年齡-"+id);        return sb.toString();    } }

(4)建立伺服器端,在伺服器端註冊RMI通訊連接埠與通訊路徑

import java.net.MalformedURLException;import java.rmi.Naming;import java.rmi.RemoteException;import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry; /** * @author BingYue */public class Process {         public static void main(String[] args){                 try {            SearchService searchService=new SearchServiceImpl();            //註冊通訊連接埠            Registry registry=LocateRegistry.createRegistry(5678);            //註冊通訊路徑            Naming.rebind("rmi://127.0.0.1:5678/searchService", searchService);            System.out.println("Service Start!");                     } catch (RemoteException e) {            e.printStackTrace();        } catch (MalformedURLException e) {            e.printStackTrace();        }    } }

(5)建立用戶端,匯入上面的實體類和介面,通過Naming.lookup()的方式調用
如果使用IDE,就可以建立一個項目,Client代碼如下:

import java.rmi.Naming; /** * @author BingYue */public class Client {         public static void main(String[] args){        try {            //調用遠程對象,注意RMI路徑與介面必須與伺服器配置一致            SearchService searchService=(SearchService)Naming.lookup("rmi://127.0.0.1:5678/searchService");            User user=searchService.findUser("100");            System.out.println(user.toString());        } catch (Exception e) {            e.printStackTrace();        }    }}

(6)分別運行服務端和用戶端,獲得遠程調用結果

(1)Remote介面:是一個不定義方法的標記介面

Public interface Remote{

}

 

Java的RMI遠程方法調用實現和應用

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.