首頁>技術>

實戰:基於Java RMI實現分散式物件通訊

本節,我們將演示如何基於Java RMI來實現分散式物件通訊。

示例概述

RMI應用程式通常包含兩個單獨的程式,即伺服器和客戶端。一個典型的伺服器程式建立一些遠端物件,使對這些物件的引用可訪問,並等待客戶端呼叫這些物件上的方法。典型的客戶端程式獲取對伺服器上一個或多個遠端物件的遠端引用,然後在其上呼叫方法。RMI提供了一種機制,伺服器和客戶端透過該機制進行通訊並來回傳遞資訊。有時將這樣的應用程式稱為分散式物件應用程式。

分散式物件應用程式需要執行以下操作。

·找到遠端物件。應用程式可以使用各種機制來獲取對遠端物件的引用。例如,應用程式可以使用RMI的簡單命名功能、RMI登錄檔註冊其遠端物件,或者應用程式可以傳遞和返回遠端物件引用,作為其他遠端呼叫的一部分。

·與遠端物件通訊。遠端物件之間的通訊詳細資訊由RMI處理。對於程式設計師而言,遠端通訊看起來類似於常規的Java方法呼叫。

·為傳遞的物件載入類定義。因為RMI使物件能夠來回傳遞,所以它提供了用於載入物件的類定義以及傳輸物件的資料的機制。

圖5-4描繪了使用RMI登錄檔獲取對遠端物件的引用的RMI分散式應用程式。伺服器呼叫登錄檔以將名稱與遠端物件關聯(或繫結)。客戶端在伺服器的登錄檔中透過其名稱查詢遠端物件,然後在其上呼叫一個方法。該圖還顯示RMI系統使用現有的Web伺服器在需要時從伺服器到客戶端以及從客戶端到伺服器為物件載入類定義。

圖5-4 RMI分散式應用程式

在本例中,同樣會有一個伺服器和客戶端,分別為RmiEchoServer和RmiEchoClient。顧名思義,本例用於演示Echo協議的內容。當RmiEchoServer接收到RmiEchoClient發起的請求時,RmiEchoServer會將請求的內容原樣返回給RmiEchoClient。

編寫RMI伺服器

RMI伺服器程式碼由一個介面Message和一個類RmiEchoServer組成。

介面定義了可以從客戶端呼叫的方法。本質上,該介面定義了遠端物件的客戶端檢視,該類提供了實現。

1.設計遠端介面Message

Message介面提供了客戶端和伺服器之間的連線。程式碼如下。

package com.waylau.java.demo.rmi;import java.rmi.Remote;import java.rmi.RemoteException;public interface Message extends Remote {/*** 傳送訊息** @param msg 訊息* @return 響應內容* @throws RemoteException*/String echoMessage(String msg) throws RemoteException;}

Message介面只有一個方法echoMessage。當呼叫該方法時,需要返回響應內容。

2.實現遠端介面Message

以下是實現Message介面的RmiEchoServer類。程式碼如下。

package com.waylau.java.demo.rmi;import java.rmi.RemoteException;import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry;import java.rmi.server.UnicastRemoteObject;public class RmiEchoServer implements Message {@Overridepublic String echoMessage(String msg) throws RemoteException {System.out.println("Client -> Server: " + msg);return msg;}public static void main(String args[]) {try {int port = ServerConstant.PORT;RmiEchoServer obj = new RmiEchoServer();Message stub = (Message) UnicastRemoteObject.exportObject(obj, 0);// 繫結遠端物件的stub到註冊中心Registry registry =LocateRegistry.getRegistry(port); // 如不指定埠,預設使用1099registry.rebind(ServerConstant.REGISTRY_NAME, stub);System.err.println("RmiEchoServer started on port: " + port);} catch (Exception e) {System.err.println("RmiEchoServer exception: " + e.toString());e.printStackTrace();}}}

RmiEchoServer類的方法echoMessage來自Message介面的定義,該方法的具體實現如下。

·在控制檯輸出接收到的內容msg。·而後將接收到的內容msg原樣返回。

RmiEchoServer類的方法main是伺服器應用的主入口。我們重點看下main方法的具體實現。

UnicastRemoteObject.exportObject靜態方法用於匯出提供的遠端物件,以便它可以從遠端客戶端接收其遠端方法的呼叫。第二個引數int指定用於偵聽該物件的傳入遠端呼叫請求的TCP埠。通常使用零值,該值指定使用匿名埠。然後,實際埠將在執行時由RMI或基礎作業系統選擇。但是,也可以使用非零值來指定用於偵聽的特定埠。成功匯出exportObject呼叫後,RmiEchoServer遠端物件已準備就緒,可以處理傳入的遠端呼叫。

exportObject方法返回匯出的遠端物件的存根。請注意,變數存根的型別必須是Message,而不是RmiEchoServer,因為遠端物件的存根僅實現匯出的遠端物件實現的遠端介面。

exportObject方法宣告它可以引發RemoteException,這是一個經過檢查的異常型別。main方法使用其try/catch塊處理此異常。如果未透過這種方式處理異常,則必須在main方法的throws子句中宣告RemoteException。

在客戶端可以在遠端物件上呼叫方法之前,客戶端必須首先獲取對該遠端物件的引用。可以透過在程式中獲得任何其他物件引用的方式來獲得引用,例如透過將引用作為方法返回值的一部分或包含此類引用的資料結構的一部分來獲取。

系統提供一種特殊型別的遠端物件RMI登錄檔,用於查詢對其他遠端物件的引用。RMI登錄檔是一個簡單的遠端物件命名服務,使客戶端能夠透過名稱獲得對遠端物件的引用。登錄檔通常僅用於查詢RMI客戶端需要使用的第一個遠端物件,然後,第一個遠端物件可能會為查詢其他物件提供支援。

java.rmi.registry.Registry遠端介面是用於繫結(或註冊)和在登錄檔中查詢遠端物件的API。java.rmi.registry.LocateRegistry類提供了靜態方法,用於合成對特定網路地址(主機和埠)上登錄檔的遠端引用。

這些方法將建立包含指定網路地址的遠端引用物件,而不執行任何遠端通訊。在本例中,我們透過port來指定特定的埠號。LocateRegistry還提供了用於在當前Java虛擬機器中建立新登錄檔的靜態方法,儘管本示例未使用這些方法。在本地主機上的RMI登錄檔中註冊了遠端物件後,任何主機上的客戶端都可以按名稱(即程式碼中的ServerConstant.REGISTRY_NAME)查詢遠端物件,獲取其引用,然後在該物件上呼叫遠端方法。登錄檔可以由主機上執行的所有伺服器共享,或者單個伺服器程序可以建立和使用其自己的登錄檔。

為了方便管理引用中的常量(比如主機地址、埠號、遠端名稱、訊息等),我們將常量定義在ServerConstant中。程式碼如下。

package com.waylau.java.demo.rmi;public interface ServerConstant {String HOST ="localhost";int PORT = 1099;String REGISTRY_NAME = "Echo Server Message";String HELLO_WORLD ="Hello World! Welcome to waylau.com!";}

編寫RMI客戶端

RMI客戶端RmiEchoClient的程式碼如下。

package com.waylau.java.demo.rmi;import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry;public class RmiEchoClient {public static void main(String[] args) {try {String host = ServerConstant.HOST;int port = ServerConstant.PORT;Registry registry = LocateRegistry.getRegistry(host, port);Message stub =(Message) registry.lookup(ServerConstant.REGISTRY_NAME);String response = stub.echoMessage(ServerConstant.HELLO_WORLD);System.out.println("Server -> Client: " + response);} catch (Exception e) {System.err.println("RmiEchoClient exception: " + e.toString());e.printStackTrace();}}}

客戶端將使用RmiEchoServer用來繫結其遠端物件的相同名稱來構建用於查詢Message遠端物件的名稱。此外,客戶端使用LocateRegistry.getRegistry API來合成對伺服器上登錄檔的遠端引用,其引數分別是伺服器的名稱及埠號。然後,客戶端在登錄檔上呼叫lookup方法,以在伺服器的登錄檔中按名稱(即程式碼中的ServerConstant.REGISTRY_NAME)查詢遠端物件。stub即為遠端物件的存根,透過呼叫stub的echoMessage方法,即實現呼叫遠端物件上的方法。其中,ServerConstant.HELLO_WORLD為echoMessage方法引數,也就是傳遞給遠端物件的訊息。

執行

在啟動應用之前,需要先啟動RMI登錄檔。RMI登錄檔是一種簡單的伺服器載入程式命名工具,它使遠端客戶端可以獲取對初始遠端物件的引用。可以使用rmiregistry命令啟動。在執行rmiregistry之前,確保該命令所執行的目錄下包含了應用的編譯檔案,即.class檔案。在Maven管理的應用中,編輯檔案通常是在應用的“target”目錄下。

以下是在Windows系統上啟動執行rmiregistry命令的方式。

start rmiregistry 1099

其中,1099是RMI伺服器所繫結的埠號。該命令不會產生任何輸出,通常在後臺執行。效果如圖5-5所示。

圖5-5 啟動RMI登錄檔

當RMI登錄檔啟動之後,就可以啟動RMI伺服器和客戶端程式了,觀察控制檯輸出內容。

可以看到,RMI伺服器輸出內容如下。

RmiEchoServer started on port: 1099Client -> Server: Hello World! Welcome to waylau.com!

RMI客戶端輸出內容如下。

Server -> Client: Hello World! Welcome to waylau.com!

本節示例,可以在java-rmi專案下找到。

本章小結

本章介紹了基於物件的分散式系統架構及常用的分散式物件系統,包括微軟DCOM(COM+)、CORBA、Java RMI。

同時我們也認識到分散式物件系統有其優點也有其缺點,在實際應用中,要根據實際的場景來考慮使用哪種分散式物件系統技術。比如,在特定的平臺,我們可以使用與該平臺所對應的分散式物件系統技術。

比如針對微軟平臺,我們可以使用DCOM(COM+)技術;在Java平臺,我們可以使用Java RMI技術。如果平臺具有多樣性,或者沒有辦法統一到相同的技術上來,那麼可以選擇使用跨平臺的分散式技術,比如CORBA。

11
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 今日推薦——100多個知名網站克隆版的開原始碼Clone-Wars