table

          RMI實(shí)用教程

          Java Remote Method Invocation ( RMI -- Java遠(yuǎn)程方法調(diào)用)允許您使用Java編寫(xiě)分布式對(duì)象。本文將介紹RMI的優(yōu)點(diǎn)以及如何將其連接到現(xiàn)有的和原有的系統(tǒng)中,以及與用Java 編寫(xiě)的組件的連接,同時(shí)給出了一個(gè)詳細(xì)的例子,可以給初學(xué)者提供一個(gè)學(xué)習(xí)范本。  

          一、RMI(遠(yuǎn)程方法調(diào)用)的組成

                一個(gè)正常工作的RMI系統(tǒng)由下面幾個(gè)部分組成:

                1、遠(yuǎn)程服務(wù)的接口定義
                2、遠(yuǎn)程服務(wù)接口的具體實(shí)現(xiàn)
                3、樁(Stub)和框架(Skeleton)文件
                4、一個(gè)運(yùn)行遠(yuǎn)程服務(wù)的服務(wù)器
                5、一個(gè)RMI命名服務(wù),它允許客戶(hù)端去發(fā)現(xiàn)這個(gè)遠(yuǎn)程服務(wù)
                6、類(lèi)文件的提供者(一個(gè)HTTP或者FTP服務(wù)器)
                7、一個(gè)需要這個(gè)遠(yuǎn)程服務(wù)的客戶(hù)端程序


          二、RMI(遠(yuǎn)程方法調(diào)用)的工作原理

          RMI系統(tǒng)結(jié)構(gòu),在客戶(hù)端和服務(wù)器端都有幾層結(jié)構(gòu)。
          --------- ----------
          | 客戶(hù) | | 服務(wù)器|
          ---------- ----------
          | |
          ------------- ----------
          | 占位程序 | | 骨干網(wǎng) |
          -------------- -----------
          | |
          ------------------------------------
          | 遠(yuǎn) 程 引 用 層 |
          ------------------------------------
          | |
          ------------------------------------
          | 傳 輸 層 |
          ------------------------------------

               方法調(diào)用從客戶(hù)對(duì)象經(jīng)占位程序(Stub)、遠(yuǎn)程引用層(Remote Reference Layer)和傳輸層(Transport Layer)向下,傳遞給主機(jī),然后再次經(jīng)傳 輸層,向上穿過(guò)遠(yuǎn)程調(diào)用層和骨干網(wǎng)(Skeleton),到達(dá)服務(wù)器對(duì)象。 占位程序扮演著遠(yuǎn)程服務(wù)器對(duì)象的代理的角色,使該對(duì)象可被客戶(hù)激活。 遠(yuǎn)程引用層處理語(yǔ)義、管理單一或多重對(duì)象的通信,決定調(diào)用是應(yīng)發(fā)往一個(gè)服務(wù)器還是多個(gè)。傳輸層管理實(shí)際的連接,并且追追蹤可以接受方法調(diào)用的遠(yuǎn)程對(duì)象。服務(wù)器端的骨干網(wǎng)完成對(duì)服務(wù)器對(duì)象實(shí)際的方法調(diào)用,并獲取返回值。返回值向下經(jīng)遠(yuǎn)程引用層、服務(wù)器端的傳輸層傳遞回客戶(hù)端,再向上經(jīng)傳輸層和遠(yuǎn)程調(diào)用層返回。最后,占位程序獲得返回值。

                要完成以上步驟需要有以下幾個(gè)步驟:

                1、生成一個(gè)遠(yuǎn)程接口
                2、實(shí)現(xiàn)遠(yuǎn)程對(duì)象(服務(wù)器端程序)
                3、編寫(xiě)服務(wù)器程序 、注冊(cè)遠(yuǎn)程對(duì)象、啟動(dòng)遠(yuǎn)程對(duì)象
                4、編寫(xiě)客戶(hù)程序
          在JDK1.5之后,用java提供的API將會(huì)更加的簡(jiǎn)單,可以參照下面的例子;

          三、例子

          1、遠(yuǎn)程接口

          接口名:com.liuxiang.rmi.download.IRMI

          該接口定義了一個(gè)方法,用于提供遠(yuǎn)程服務(wù);

           

          /**
           *
           */
          package com.liuxiang.rmi.download;

          import java.rmi.Remote;
          import java.rmi.RemoteException;

          /**
           * 遠(yuǎn)程對(duì)象接口
           * @author liuxiang
           * 2007-8-30 下午09:39:15   
           *
           */
          public interface IRMI extends Remote{
              public Object invoke(ITask task) throws RemoteException;
          }

          2、實(shí)現(xiàn)遠(yuǎn)程對(duì)象(服務(wù)器端程序)

          類(lèi)名:com.liuxiang.rmi.download.IRMIImpl

          實(shí)現(xiàn)了遠(yuǎn)程接口定義的方法;該實(shí)現(xiàn)遠(yuǎn)程對(duì)象中,調(diào)用了傳入?yún)?shù)的task.doWork()方法,同時(shí)執(zhí)行一個(gè)本地調(diào)用,調(diào)用一個(gè)播放Mp3的代碼段ProcessCaller.callMp3();


           

          /**
           *
           */
          package com.liuxiang.rmi.download;

          import java.rmi.RemoteException;
          import java.rmi.server.UnicastRemoteObject;

          import com.liuxiang.callwindow.ProcessCaller;

          /**
           * 遠(yuǎn)程對(duì)象的實(shí)現(xiàn)
           * @author liuxiang
           * 2007-8-30 下午09:41:32   
           *
           */
          public class IRMIImpl extends UnicastRemoteObject implements IRMI {

              protected IRMIImpl() throws RemoteException {
                  super();
              }

              /**
               *
               */
              private static final long serialVersionUID = 6131922116577454476L;

              /* (non-Javadoc)
               * @see com.liuxiang.rmi.download.IRMI#invoke(com.liuxiang.rmi.download.ITask)
               */
              public Object invoke(ITask task) throws RemoteException {
                  System.out.println("注意:這是一個(gè)遠(yuǎn)程調(diào)用");
                  Object obj = task.doWork();
                  System.out.println("調(diào)用ITask.doWork()方法的返回值:"+obj.toString());
                  //客戶(hù)端調(diào)用,可以在服務(wù)器端播放需要的音樂(lè)
                  ProcessCaller.callMp3();
                  return obj;
              }

          }


          3、播放Mp3代碼段的源代碼如下:

           

          /**
           *
           */
          package com.liuxiang.callwindow;

          /**
           * 在java中調(diào)用windows程序
           * @author liuxiang 2007-8-30 下午10:26:20
           *
           */
          public class ProcessCaller {
              /**
               * 調(diào)用Windows程序
               * 利用Windows Media Player播放mp3音樂(lè)
               */
              public static void callMp3() {
                  Runtime ru = Runtime.getRuntime();
                  try {
                      // 調(diào)用播放器文件播放指定MP3
                      Process p1 = ru
                              .exec("C:\Program Files\Windows Media Player\wmplayer F:/music/lx/劉若英-后來(lái).mp3");
                  } catch (Exception e) {

                  }
              }

              /**
               * @param args
               */
              public static void main(String[] args) {
                  callMp3();
              }

          }

          4、任務(wù)接口

          該接口定義了遠(yuǎn)程方法需要傳遞的參數(shù)


           

          /**
           *
           */
          package com.liuxiang.rmi.download;

          import java.io.Serializable;

          /**
           * 任務(wù)接口
           * @author liuxiang
           * 2007-8-30 下午09:35:53   
           *
           */
          public interface ITask extends Serializable{
              public Object doWork();
          }


          5、任務(wù)接口實(shí)現(xiàn)

          該實(shí)現(xiàn)定義了遠(yuǎn)程方法需要傳遞的參數(shù)

           

          package com.liuxiang.rmi.download;

          /**
           * 任務(wù)實(shí)現(xiàn)類(lèi)
           * @author liuxiang
           * 2007-8-31 上午09:08:57   
           *
           */
          public class TaskImpl implements ITask{

              public Object doWork() {
                  System.out.println("當(dāng)前程序處于遠(yuǎn)程調(diào)用中");
                  return "動(dòng)態(tài)上載對(duì)象的返回值";
              }
             
          }

          6、編寫(xiě)服務(wù)器程序 、注冊(cè)遠(yuǎn)程對(duì)象、啟動(dòng)遠(yuǎn)程對(duì)象

          代碼:遠(yuǎn)程對(duì)象的注冊(cè)類(lèi) 該類(lèi)應(yīng)該在服務(wù)器端執(zhí)行 執(zhí)行之后, 該機(jī)器將變?yōu)镽MI服務(wù)器 客戶(hù)端可以通過(guò)正確的url來(lái)訪問(wèn);服務(wù)器上的遠(yuǎn)程對(duì)象;執(zhí)行對(duì)外報(bào)露的方法

           

          /**
           *
           */
          package com.liuxiang.rmi.download;

          import java.rmi.Naming;
          import java.rmi.registry.LocateRegistry;
          import java.rmi.registry.Registry;

          /**
           * 遠(yuǎn)程對(duì)象的注冊(cè)類(lèi) 該類(lèi)應(yīng)該在服務(wù)器端執(zhí)行 執(zhí)行之后,
           * 該機(jī)器將變?yōu)镽MI服務(wù)器 客戶(hù)端可以通過(guò)正確的url來(lái)訪問(wèn)
           * 服務(wù)器上的遠(yuǎn)程對(duì)象;執(zhí)行對(duì)外報(bào)露的方法
           *
           * @author liuxiang 2007-8-30 下午09:44:54
           *
           */
          public class RMIServer {
              /**
               * 如果沒(méi)有創(chuàng)建一個(gè)Registry,Naming是不會(huì)幫助你創(chuàng)建的。 還是自己手工創(chuàng)建的比較的好
               *
               * 盡量用下面的自己封裝的bind方法來(lái)注冊(cè)遠(yuǎn)程對(duì)象
               *
               * @throws Exception
               */
              public static void registRemoteObject() throws Exception {
                  IRMIImpl impl = new IRMIImpl();
                  Naming.rebind("rmi://219.233.8.97:1111/mytask", impl);
                  System.out.println("bound success!");
              }

              /**
               * 創(chuàng)建一個(gè)Registry對(duì)象
               *
               * @return 返回一個(gè)Registry對(duì)象
               */
              private static Registry createRegistry() {
                  Registry registry = null;
                  int port = 1111;
                  try {
                      registry = LocateRegistry.getRegistry(port);
                      registry.list();
                      System.out.println("Register the exist server!");
                  } catch (final Exception e) {
                      try {
                          registry = LocateRegistry.createRegistry(port);
                          System.out.println("Register the exist server!port=" + port);
                      } catch (final Exception ee) {
                          ee.printStackTrace();
                      }
                  }
                  return registry;
              }

              /**
               * 將對(duì)象注冊(cè)到rmi服務(wù)器上
               */
              public static void bind() {
                  Registry registry = null;
                  registry = createRegistry();
                  try {
                      IRMIImpl impl = new IRMIImpl();
                      registry.rebind("mytask", impl);
                      System.out.println("mytask server start!");
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }

              /**
               * @param args
               */
              public static void main(String[] args) {
                  try {
                      bind();
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }

          }

          運(yùn)行該服務(wù)端代碼后,將會(huì)注冊(cè)一個(gè)遠(yuǎn)程服務(wù)對(duì)象,通過(guò)恰當(dāng)?shù)腢RL可以訪問(wèn)遠(yuǎn)程對(duì)象中的方法;運(yùn)行后的結(jié)果如下:

          Register the exist server!port=1111
          mytask server start!

          7、編寫(xiě)客戶(hù)程序

          代碼首先獲取一個(gè)遠(yuǎn)程對(duì)象,然后如同本地調(diào)用一樣,調(diào)用遠(yuǎn)程對(duì)象中的方法。

           

          /**
           *
           */
          package com.liuxiang.rmi.download;

          import java.rmi.Naming;

          /**
           * @author liuxiang
           * 2007-8-30 下午09:47:41   
           *
           */
          public class RMIClient {
              /**
               * 調(diào)用遠(yuǎn)程對(duì)象中的方法
               * @throws Exception
               */
              public static void getRemoteObject() throws Exception{
                  IRMI obj = (IRMI)Naming.lookup("rmi://localhost:1111/mytask");    //得到遠(yuǎn)程發(fā)布的服務(wù)
                  TaskImpl task = new TaskImpl();
                  Object result = obj.invoke(task);    //調(diào)用遠(yuǎn)程服務(wù)的方法
                  System.out.println(result.toString());
              }

              /**
               * @param args
               */
              public static void main(String[] args) {
                  try {
                      getRemoteObject();
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }

          }

          最后,運(yùn)行客戶(hù)端代碼,可以看到控制臺(tái)分別輸出了如下的內(nèi)容:

          Server端輸出了更多的內(nèi)容,如下:

           

          Register the exist server!port=1111
          mytask server start!
          注意:這是一個(gè)遠(yuǎn)程調(diào)用
          當(dāng)前程序處于遠(yuǎn)程調(diào)用中
          調(diào)用ITask.doWork()方法的返回值:動(dòng)態(tài)上載對(duì)象的返回值
          同時(shí)可以看到,會(huì)調(diào)用了Windows的Mediaplay播放本地磁盤(pán)的Mp3歌曲;

          Client端輸入了如下內(nèi)容:

           

          動(dòng)態(tài)上載對(duì)象的返回值
           
          四、RMI介紹

          RMI(Remote Method Invocation,遠(yuǎn)程方法調(diào)用)是用Java在JDK1.1中實(shí)現(xiàn)的,它大大增強(qiáng)了Java開(kāi)發(fā)分布式應(yīng)用的能力。Java作為一種風(fēng)靡一時(shí)的網(wǎng)絡(luò)開(kāi)發(fā)語(yǔ)言,其巨大的威力就體現(xiàn)在它強(qiáng)大的開(kāi)發(fā)分布式網(wǎng)絡(luò)應(yīng)用的能力上,而RMI就是開(kāi)發(fā)百分之百純Java的網(wǎng)絡(luò)分布式應(yīng)用系統(tǒng)的核心解決方案之一。其實(shí)它可以被看作是RPC的Java版本。但是傳統(tǒng)RPC并不能很好地應(yīng)用于分布式對(duì)象系統(tǒng)。而Java RMI 則支持存儲(chǔ)于不同地址空間的程序級(jí)對(duì)象之間彼此進(jìn)行通信,實(shí)現(xiàn)遠(yuǎn)程對(duì)象之間的無(wú)縫遠(yuǎn)程調(diào)用。 

          RMI目前使用Java遠(yuǎn)程消息交換協(xié)議JRMP(Java Remote Messaging Protocol)進(jìn)行通信。JRMP是專(zhuān)為Java的遠(yuǎn)程對(duì)象制定的協(xié)議。因此,Java RMI具有Java的"Write Once,Run Anywhere"的優(yōu)點(diǎn),是分布式應(yīng)用系統(tǒng)的百分之百純Java解決方案。用Java RMI開(kāi)發(fā)的應(yīng)用系統(tǒng)可以部署在任何支持JRE(Java Run Environment Java,運(yùn)行環(huán)境)的平臺(tái)上。但由于JRMP是專(zhuān)為Java對(duì)象制定的,因此,RMI對(duì)于用非Java語(yǔ)言開(kāi)發(fā)的應(yīng)用系統(tǒng)的支持不足。不能與用非Java語(yǔ)言書(shū)寫(xiě)的對(duì)象進(jìn)行通信。

          RMI為采用Java對(duì)象的分布式計(jì)算提供了簡(jiǎn)單而直接的途徑。這些對(duì)象可以是新的Java對(duì)象,也可以是圍繞現(xiàn)有API的簡(jiǎn)單的Java包裝程序。Java體現(xiàn)了“編寫(xiě)一次就能在任何地方運(yùn)行的模式。而RMI可將Java模式進(jìn)行擴(kuò)展,使之可在任何地方運(yùn)行”。

            因?yàn)镽MI是以Java為核心的,所以,它將Java的安全性和可移植性等強(qiáng)大功能帶給了分布式計(jì)算。您可將代理和梢?務(wù)邏輯等屬性移動(dòng)到網(wǎng)絡(luò)中最合適的地方。如果您要擴(kuò)展Java在系統(tǒng)中的使用,RMI將使您充分利用其強(qiáng)大功能。

            RMI可利用標(biāo)準(zhǔn)Java本機(jī)方法接口JNI與現(xiàn)有的和原有的系統(tǒng)相連接。RMI還可利用標(biāo)準(zhǔn)JDBC包與現(xiàn)有的關(guān)系數(shù)據(jù)庫(kù)連接。RMI/JNI和RMI/JDBC相結(jié)合,可幫助您利用RMI與目前使用非Java語(yǔ)言的現(xiàn)有服務(wù)器進(jìn)行通信,而且在您需要時(shí)可擴(kuò)展Java在這些服務(wù)器上的使用。RMI可幫助您在擴(kuò)展使用時(shí)充分利用Java的強(qiáng)大功能。

           

          posted on 2009-08-11 17:50 小卓 閱讀(146) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): EJB


          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 通海县| 横峰县| 许昌市| 敦化市| 宝清县| 库车县| 长岛县| 钟祥市| 阜城县| 太康县| 新竹县| 香港| 通州区| 北安市| 铜鼓县| 含山县| 额济纳旗| 苏州市| 新乡市| 扶余县| 伊宁县| 文昌市| 宜城市| 襄汾县| 海兴县| 山阳县| 漳浦县| 海城市| 南江县| 鄂伦春自治旗| 黔南| 广昌县| 凯里市| 永寿县| 友谊县| 莒南县| 叙永县| 独山县| 稻城县| 梧州市| 阳新县|