天天看點

Java RMI 介紹

java rmi 指的是遠端方法調用 (remote method invocation)。它是一種機制,能夠讓在某個 java 虛拟機上的對象調用另一個 java 虛拟機中的對象上的方法。是以,rmi相關對象必須運作在java虛拟機中。

在java中,隻要一個類extends了<code>java.rmi.remote</code>接口,即可成為存在于伺服器端的遠端對象,供用戶端通路并提供一定的服務。javadoc描述:remote 接口用于辨別其方法可以從非本地虛拟機上調用的接口。任何遠端對象都必須直接或間接實作此接口。隻有在“遠端接口”(擴充 <code>java.rmi.remote</code>的接口)中指定的這些方法才可遠端使用。

在rmi中,當對象在虛拟機之間傳遞時,接收端虛拟機并不是複制一個遠端對象,而是通過rmi接收一個遠端對象的stub。這個stub就是對遠端對象的引用,它其實是一個對遠端對象的代理。接收端在本地調用了stub的方法,也就相當于調用了遠端對象的方法。

接收端持有的遠端對象的stub和遠端對象實作的必須是同一組接口,這樣才能将stub轉換成遠端對象接口類型,進而實作通過stub調用遠端對象的方法。

下面我們就按照以上四步寫一個分布式的hello word的例子來示範一下這個過程

編寫rmi應用的第一步就是先定義遠端接口。遠端接口必須繼承<code>java.rmi.remote</code>接口,并且聲明自己的遠端方法。為了處理遠端方法發生的各種異常,每一個遠端方法必須抛出一個<code>java.rmi.remoteexception</code>異常。

這個遠端接口隻定義了一個遠端方法 <code>sayhello()</code>,遠端方法在調用的時候有可能失敗比如發生網絡問題或者server挂掉,此時遠端方法會抛出<code>remoteexception</code>異常。

開發接口的實作類,即具體的遠端對象,在遠端對象中實作遠端接口中定義的方法。

在server端隻需要做兩件事:

server端的main方法在建立一個遠端對象來提供服務時,此遠端對象必須被導出才能被遠端調用者調用。靜态方法<code>unicastremoteobject.exportobject()</code>負責導出我們定義好的遠端對象,它的第一個參數就是要到導出的遠端對象,第二個參數是接收遠端調用的tcp端口,這個值是0,它代表任意tcp端口。

<code>exportobject()</code>還會傳回一個導出的遠端對象的存根,注意,前面講過了這個stub的類型必須和遠端對象的接口類型一緻,因為這個存根是要發送給client端進行調用。同時這個方法還會抛出一個<code>remoteexception</code>檢查異常。

當<code>exportobject()</code>方法被執行後,運作時會在一個新的<code>server socket</code>或共享<code>server socket</code>上進行監聽,來接收對遠端對象的遠端調用。傳回的存根對象和遠端對象繼承的是同一套remote接口,并且還它還包含了供client端口通路的主機ip和端口資訊。

前面導出了遠端對象的stub,它必須還能被client端找到并調用。為此,java rmi 提供了 registry api 可以允許應用程式把一個名稱和遠端對象的存根綁定在一起,這樣client就可以通過這個綁定的名稱很友善的查找到需要調用的遠端對象了。

一旦遠端對象在server端導出并注冊,client就可以通過綁定的名稱獲得遠端對象的引用,然後調用遠端方法。

靜态方法<code>registry registry=locateregistry.createregistry(1099);</code>會傳回一個實作了<code>java.rmi.registry.registry</code>接口的存根,并且在伺服器本機的端口(預設是1099)上進行注冊,傳回的registry存根通過調用<code>bind()</code>方法在registry中把一個字元串名稱和遠端對象存根綁定在一起。

用戶端首先通過<code>locateregistry.getregistry("localhost")</code>方法獲得registry的存根,然後再執行registry存根的<code>lookup()</code>方法從伺服器registry中獲得遠端對象的存根,最後用戶端在遠端對象存根上執行<code>sayhello()</code>方法。整個過程:

用戶端通過遠端對象存根中的ip和端口打開一個伺服器連接配接,并且序列化請求資料

伺服器端接收請求并且轉發請求到遠端對象調用服務方法,并且序列化運作結果發送給用戶端

用戶端接收資料反序列化,把最終結果傳回給調用者

啟動server,然後再啟動client,控制台列印:

java rmi中用到了經典的工廠模式,先介紹下java rmi應用的一些角色:

server:生産各種遠端對象

client:通過命名伺服器rmiregistry擷取遠端對象的存根

rmiregistry:具體處理client與server的交流

下面這幅圖示範了整個步驟,下圖中先做如下假設:

有兩個遠端服務接口可供client調用,factory和product接口

factoryimpl類實作了factory接口,productimpl類實作了product接口

Java RMI 介紹