Java RMI(遠程方法調用)開發


參考

https://docs.oracle.com/javase/7/docs/platform/rmi/spec/rmi-arch2.html

http://www.cnblogs.com/wxisme/p/5296441.html

http://blog.csdn.net/qb2049_xg/article/details/3278672 

http://classfoo.com/ccby/article/p1wgbVn

http://www.cnblogs.com/yin-jingyu/archive/2012/06/14/2549361.html

RMI與RPC

RMI在我看來更像Java專屬的RPC,或者說純面向對象的RPC。跟RPC一樣是分布式非常重要的內容,也是Java消息中間件的基礎。

RMI原理

本質就是在兩處同步一個Java對象(可以基於 JDK 本身的對象序列化或者基於 HTTP 協議的數據序列化)A 和 A!,但其中一個Java對象A進行方法調用時,通過RMI的代理能力轉發給另一個Java對象A!進行執行,並將A!的執行結果作為A的執行結果。這樣就實現了,運算流程的分布式計算。一般這兩個對象存在於兩台機器上。

  1. 將可以遠程調用的對象進行序列化,然后綁定到RMI Server(被調方,運行者)中作為存根(stub)
  2. RMI Client 會先去下載stub反序列化然后發起client調用,RMI 底層(RMI Interface Layer & Transport Layer)會講請求參數封裝發送到RMI Server 
  3. RMI Server 接收到封裝的參數,傳遞給樁(skeleton),由樁解析參數並且以參數調用對應的存根()stub方法。
  4. 存根方法在RMI Server執行完畢之后,返回結果將被RMI底層封裝並傳輸給RMI Client(也就是主調方,調用者)

目前的Java版本已經不需要創建skeleton,也不需要rmic來編譯stub了,但是我學習的時候還是使用的rmic編譯的stub,所以示例也是這樣做的。

RMI Server編寫

編寫RMI Server Interface,這個也會被用在客戶端(RMI Client),供客戶端使用。列出了開放遠程調用的接口

 1 package org.lyh.server;
 2 
 3 import java.rmi.Remote;
 4 import java.rmi.RemoteException;
 5 
 6 /**
 7  * Created by lvyahui on 2016/4/22.
 8  */
 9 public interface ITimeServer extends Remote {
10     long getServerTime() throws RemoteException;
11     int add(int a,int b) throws RemoteException;
12 }

編寫時間Server 接口

 1 package org.lyh.server.impl;
 2 
 3 import org.lyh.server.ITimeServer;
 4 
 5 import java.rmi.RemoteException;
 6 import java.rmi.server.RMIClientSocketFactory;
 7 import java.rmi.server.RMIServerSocketFactory;
 8 import java.rmi.server.UnicastRemoteObject;
 9 
10 /**
11  * Created by lvyahui on 2016/4/22.
12  */
13 public class TimeServer extends UnicastRemoteObject implements ITimeServer {
14 
15     public TimeServer(int port) throws RemoteException {
16         super(port);
17     }
18 
19     public TimeServer() throws RemoteException {
20     }
21 
22     public TimeServer(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException {
23         super(port, csf, ssf);
24     }
25 
26     @Override
27     public long getServerTime() throws RemoteException {
28         return System.currentTimeMillis();
29     }
30 
31     @Override
32     public int add(int a, int b) throws RemoteException {
33         return a + b;
34     }
35 }

將編寫好的Server實現對象綁定到Java RMI的名字服務上

 1 package org.lyh;
 2 
 3 import org.lyh.server.impl.TimeServer;
 4 
 5 import java.net.MalformedURLException;
 6 import java.rmi.Naming;
 7 import java.rmi.RemoteException;
 8 
 9 public class Main {
10     public static void main(String[] args) {
11         try {
12             TimeServer timeServer = new TimeServer();
13             /* 綁定到JVM 的 RMI Server上*/
14 //            Naming.bind("t1",timeServer);
15 //            Naming.rebind("t1",timeServer);
16             /* 當RMI注冊server是指定了端口時或者不在本機運行時,需要這樣寫*/
17             Naming.rebind("//localhost/t1",timeServer);
18             System.out.println("Bind is Finish");
19         } catch (RemoteException e) {
20             e.printStackTrace();
21         } catch (MalformedURLException e) {
22             e.printStackTrace();
23         }
24     }
25 }

這時,要用rmic進一步編譯TimeServer.class文件,得到TimeServer_stub.class 存根對象文件。如果不用rmic編譯的方式,也可以通過寫代碼的方式獲取stub。

因為我是使用IDEA開發的,所以我進入了RMI\out\production\RMI目錄編譯,執行rmic org.lyh.server.impl.TimeServer

 

這樣會在相同目錄下生成TimeServer_stub.class 文件

然后啟動RMI名字注冊服務,執行 rmiregistry 命令(jdk\bin下的一個腳本),可以執行 rmiregistry port執行端口,否則默認就是1099

下面可以執行org.lyh.Main@main方法了,將存根綁定(注冊)到RMI 名字服務上,名字為t1

RMI Client編寫

RMI client就簡單了,拉取存根,然后發起調用,調用被傳輸到Server執行,並獲取到執行結果,返回結果直接由接口方法return得到。

 1 package org.lyh.client;
 2 
 3 import org.lyh.server.ITimeServer;
 4 
 5 import java.net.MalformedURLException;
 6 import java.rmi.Naming;
 7 import java.rmi.NotBoundException;
 8 import java.rmi.RemoteException;
 9 
10 /**
11  * Created by lvyahui on 2016/4/22.
12  */
13 public class TimeClient {
14     public static void main(String[] args) {
15         try {
16            ITimeServer iTimeServer = (ITimeServer) Naming.lookup("rmi://192.168.18.1/t1");
17             System.out.println(iTimeServer.getServerTime());
18             System.out.println(iTimeServer.add(3,7));
19         } catch (NotBoundException e) {
20             e.printStackTrace();
21         } catch (MalformedURLException e) {
22             e.printStackTrace();
23         } catch (RemoteException e) {
24             e.printStackTrace();
25         }
26     }
27 }

為了更加真實,我將這個Client上傳到虛擬機上編譯運行

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM