RMI實例入門

 RMI實例入門

一篇簡單實用可以快速入門的RMI的好文章.

背景:
   偶參與的一個項目使用了IBM 的workflow 工作流服務器,現在這個系統需要和其他系統做整合,外部的系統需要直接與工作流服務器做操作,查閱了IBM的文檔,發現workflow對外提供了 java RMI 接口,所以 我摸索了一下java RMI 的使用,整理一份RMI入門的文檔,希望給對大家有所幫助。
 
一 .RMI概述
RMI(Remote Method Invocation)
    RMI是分佈式對象軟件包,它簡化了在多臺計算機上的JAVA應用之間的通信。必須在jdk1.1以上

RMI用到的類
     java.rmi.Remote                   所有可以被遠程調用的對象都必須實現該接口
     java.rmi.server.UnicastRemoteObject  所有可以被遠程調用的對象都必須擴展該類
 
什麼是RMI
    遠程方法調用是一種計算機之間對象互相調用對方函數,啓動對方進程的一種機制,
使用這種機制,某一臺計算機上的對象在調用另外一臺計算機上的方法時,使用的程
序語法規則和在本地機上對象間的方法調用的語法規則一樣。

優點
這種機制給分佈計算的系統設計、編程都帶來了極大的方便。
只要按照RMI規則設計程序,可以不必再過問在RMI之下的網絡細節了,如:TCP和Socket等等。
任意兩臺計算機之間的通訊完全由RMI負責。調用遠程計算機上的對象就像本地對象一樣方便。
 
1、面向對象:
RMI可將完整的對象作爲參數和返回值進行傳遞,而不僅僅是預定義的數據類型。
也就是說,可以將類似Java哈西表這樣的複雜類型作爲一個參數進行傳遞。
 
2、可移動屬性:
RMI可將屬性從客戶機移動到服務器,或者從服務器移動到客戶機。
 
3、設計方式:
對象傳遞功能使您可以在分佈式計算中充分利用面向對象技術的強大功能,如二層和三層結構系統。
如果用戶能夠傳遞屬性,那麼就可以在自己的解決方案中使用面向對象的設計方式。
所有面向對象的設計方式無不依靠不同的屬性來發揮功能,如果不能傳遞完整的對象——包括實現和類型
——就會失去設計方式上所提供的優點。
 
4、安全性:
RMI使用Java內置的安全機制保證下載執行程序時用戶系統的安全。
RMI使用專門爲保護系統免遭惡意小程序侵害而設計的安全管理程序。
5、便於編寫和使用
RMI使得Java遠程服務程序和訪問這些服務程序的Java客戶程序的編寫工作變得輕鬆、簡單。
遠程接口實際上就是Java接口。
爲了實現RMI的功能必須創建遠程對象任何可以被遠程調用的對象必須實現遠程接口。但遠程
接口本身並不包含任何方法。因而需要創建一個新的接口來擴展遠程接口。
新接口將包含所有可以遠程調用的方法。遠程對象必須實現這個新接口,由於新的接口擴展了
遠程接口,實現了新接口,就滿足了遠程對象對實現遠程接口的要求,所實現的每個對象都將
作爲遠程對象引用。
 
個人總結:
    RMI說白了,就是提供了一種遠程的方法調用。 這種調用簡單方便,可以傳遞複雜java對象。現在流行的j2ee中的EJB的底層實現技術就是RMI,EJB的調用就是經過封裝的,更高級的RMI調用。


下面我們就來寫一個RMI的程序:
 
一.創建RMI程序的6個步驟:
1、定義一個遠程接口的接口,該接口中的每一個方法必須聲明它將產生一個RemoteException異常。
2、定義一個實現該接口的類。
3、使用RMIC程序生成遠程實現所需的殘根和框架。
4、創建一個服務器,用於發佈2中寫好的類。
5. 創建一個客戶程序進行RMI調用。
6、啓動rmiRegistry並運行自己的遠程服務器和客戶程序。
 
二. 程序詳細說明
 
1.定義一個遠程接口的接口,該接口中的每一個方法必須聲明它將產生一個RemoteException異常。
 
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface I_Hello extends java.rmi.Remote   //需要從Remote繼承
{
       public String SayHello() throws RemoteException;   //需要拋出remote異常
}

   上面例子我們定義一個返回字符串的遠程方法 SayHello(),這個遠程接口 I_Hello必須是public的 ,它必須從java.rmi.Remote繼承而來,接口中的每一個方法都必須拋出遠程異常java.rmi.RemoteException。

拋出這個異常的原因
由於任何遠程方法調用實際上要進行許多低級網絡操作,因此網絡錯誤可能在調用過程中隨時發生。
因此,所有的RMI操作都應放到try-catch塊中。
  
2、定義一個實現該接口的類。
 
 import java.io.PrintStream;
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
 
public class Hello extends UnicastRemoteObject   //必須從UnicastRemoteObject  繼承
                   implements I_Hello
{
        public Hello() throws RemoteException     //需要一個拋出Remote異常的默認初始化方法
        {
        }
 
        public String SayHello()     //這個是實現I_Hello接口的方法
        {
           return "Hello world !!";
        }
}
 
實現接口的類必須繼承UnicastRemoteObject類。
擴展java.rmi.server.UnicastRemoteObject
UnicastRemoteObject顧名思義,是讓客戶機與服務器對象實例建立一對一的連接。
 
3、使用RMIC程序生成遠程實現所需的殘根Stub 和 框架。
   2中的Hello 編譯好以後,我們就可以用RMIC命令來生成殘根Stub
   在Dos窗口裏,到Hello.class 所在目錄,運行以下命令:
   rmic Hello
   
   命令執行完以後,將會在當前目錄生成一個 Hello_Stub.class 這個就是我們遠程調用時需要的類
 
參考:
在RMI中,客戶機上生成的調動調用參數和反調動返回值的代碼稱爲殘根。有的書上稱這部分代碼爲“主幹”。
服務器上生成的反調動調用參數和進行實際方法調用調動返回值的代碼稱爲框架。
生成殘根和框架的工具
Rmic命令行工具(RMI Compiler)
格式:
Rmic classname
 
4、創建一個服務器,用於發佈2中寫好的類。
 
    import java.rmi.*;
public class RMI_Server
{
    public static void main(String[] args)
    {
        try
        {
            Hello hello = new Hello();                //實例化要發佈的類
            Naming.rebind("RMI_Hello", hello);      //綁定RMI名稱 進行發佈
            System.out.println("=== Hello server Ready === ");
        }
        catch(Exception exception)
        {
            exception.printStackTrace();
        }
    }
}
 
5. 創建一個客戶程序進行RMI調用。
 
import java.rmi.*;
public class RMI_Client {
    public static void main(String[] args) {
        try
        {
           I_Hello hello = (I_Hello) Naming.lookup("RMI_Hello");  //通過RMI名稱查找遠程對象
            System.out.println(hello.SayHello());                        //調用遠程對象的方法
        } catch (Exception e)
        {
          e.printStackTrace();
        }
    }

}

Naming.lookup("RMI_Hello") 其中的參數“RMI_Hello”只是針對本機的RMI查找,如果是異地的RMI調用請參照  rmi://127.0.0.1:1099/RMI_Hello       端口1099是默認的RMI端口,如果你啓動 rmiregistry 的時候(見第6點)沒有指定特殊的端口號,默認就是1099
 
到此 我們 所有的代碼編寫都完成了,不過不要急着去運行,請跟隨第6點去運行,因爲rmi 調用還會遇到一些特別的情況,偶花了牛勁,才找到原因的,許多剛用RMI的人,常常被這些問題搞得吐血
 
6、啓動rmiRegistry並運行自己的遠程服務器和客戶程序。
 1)服務器的運行
    先在DOS下運行 rmiregistry     這個命令是開啓RMI的註冊服務,開啓以後我們的server程序才能調用rebing方法發佈我們的類
 
    然後,運行我們的server程序  RMI_Server    這裏是最容易出錯的,參見下面注意事項。
     注意:
         如果提示找不到Stub類,這個需要用下面的命令來運行
 java.exe -Djava.rmi.server.codebase=file:/E:/MIS_Interface/momo/TestEasy/classes/  RMI_Server
 
藍字部分指定了stub類的路徑。
 
  有人會問,我已經把stub 通過-classpath 加到類路徑裏面了,爲什麼還沒有提示這個錯誤呢?原因是這樣的: 這裏提示的找不到stub類,不是由你寫的RMI_Server這個程序引起的,是由rmi註冊服務器報告的異常,也就是我們前面啓動的 rmiregistry ,因爲你寫的RMI_Server 要求RMI註冊服務器註冊一個新的類,自然RMI服務器必須知道你的類放在哪裏,所以我們通過  -Djava.rmi.server.codebase 這個運行參數來指定
  你也可以通過修改操作系統的classpath 環境變量 來指定stub的位置,只不過太麻煩
 
2) 客戶端的運行
      直接運行RMI_Client  即可  注意 把 Stub 和 接口 I_Hello 加到類路徑裏
  
    通常第一次運行 客戶端都會報一個錯誤:   Access  XXXX 不記得具體的了,反正就是“訪問權限限制”, 這是因爲RMI的服務需要授權,外部程序才能訪問,所以我們要改動 jre的安全配置文件,來開放權限,  具體如下:
 
   打開你的jdk目錄下的這個文件 C:/Program Files/Java/jdk1.5.0_04/jre/lib/security/java.policy
在文件最後加入下面代碼:
 grant {
           permission java.net.SocketPermission "*:1024-65535",
                "connect,accept";
           permission java.net.SocketPermission "*:80","connect";
        };
此代碼,開放了端口的connect訪問權限
 
注意 你應該修改服務器那臺機子的安全配置文件,也就是你運行 rmiregistry 和 RMI_Server的機子
另 外,很多人修改完以後,仍然報這個錯誤,多數情況是由於你沒有修改到正確的jdk 下的文件,而是修改到其他jdk的文件, 我們安裝oracle , Weblogic等等軟件的時候都會自帶一個 jdk,他們會自動在操作系統的環境變量裏面 加入jdk的路徑,所以,你先要確定你運行服務器端程序是用哪個jdk,再修改這個jdk下的配置文件,確定當前jdk的路徑很簡單  開始 -》運行-》rmiregistry 看看這個DOS窗口標題 的路徑,就是你當前系統默認jdk的路徑了
 
客戶端正常運行以後,就會出現以下結果:
Hello world !!

這些字符是通過RMI調用遠程服務器的類返回的結果

 
發佈了36 篇原創文章 · 獲贊 0 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章