在java中,隻要一個類繼承了<code>java.rmi.remote</code>接口,即可成為存在于伺服器端的遠端對象,供用戶端通路并提供一定的服務。javadoc描述:remote 接口用于辨別其方法可以從非本地虛拟機上調用的接口。任何遠端對象都必須直接或間接實作此接口。隻有在“遠端接口”(擴充 java.rmi.remote 的接口)中指定的這些方法才可遠端使用。
編寫rmi應用的第一步就是先定義遠端接口。遠端接口必須繼承<code>java.rmi.remote</code>接口,并且聲明自己的遠端方法。為了處理遠端方法發生的各種異常,每一個遠端方法必須抛出一個<code>java.rmi.remoteexception</code>異常。
這個遠端接口隻定義了一個遠端方法 <code>sayhello()</code>,遠端方法在調用的時候有可能失敗比如發生網絡問題或者server挂掉,此時遠端方法會抛出<code>remoteexception</code>異常。
開發接口的實作類,即具體的遠端對象,在遠端對象中實作遠端接口中定義的方法。
在server端隻需要做兩件事:
建立并導出遠端對象
用java rmi registry 注冊遠端對象
下面是一個server端的程式:
server端的main方法在建立一個遠端對象來提供服務時,此遠端對象必須被導出才能被遠端調用者調用。靜态方法<code>unicastremoteobject.exportobject()</code>負責導出我們定義好的遠端對象,并用任意一個tcp端口來接收遠端方法調用,同時,它還會傳回一個存根,這個存根将會發送給client端進行調用。當<code>exportobject()</code>方法被執行後,運作時會在一個新的server socket或共享server socket上進行監聽,來接收對遠端對象的遠端調用。傳回的存根對象和遠端對象繼承的是同一套remote接口(為了實作代理模式),并且還它還包含了供client端口通路的主機ip和端口資訊。
為了使client能夠調用遠端對象的方法,client必須持有遠端對象的存根,為此,java rmi 提供了registry api 可以允許應用程式把一個名稱和遠端對象的存根綁定在一起,這樣client就可以通過這個綁定的名稱很友善的查找到需要調用的遠端對象了,在這裡可以把registry看做是一個名稱服務,實作了工廠模式(提供具體的遠端對象)和代理模式(代理server端具體處理client端的請求)。
一旦遠端對象在server端導出并注冊,client就可以通過綁定的名稱獲得遠端對象的引用,然後調用遠端方法。
靜态方法<code>registry registry=locateregistry.getregistry()</code>會傳回一個實作了<code>java.rmi.registry.registry</code>接口的存根,并且在伺服器本機的端口(預設是1099)上進行注冊,傳回的registry存根通過調用bind()方法在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接口