Java RMI詳解[轉]

RMI:遠程方法調用(Remote Method Invocation)。可以讓在某個java虛擬機上的對象像調用本地對象同樣調用另外一個java 虛擬機中的對象上的方法。java

RMI遠程調用步驟:bash

1,客戶對象調用客戶端輔助對象上的方法服務器

2,客戶端輔助對象打包調用信息(變量,方法名),經過網絡發送給服務端輔助對象網絡

  1. JAVA_HOME=/home/name/jdk/jdk1.5.0_15  app

  2. export JAVA_HOME  函數

  3. PATH=$JAVA_HOME/bin:$PATH  工具

  4. export PATH  oop

  5. CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:/home/name/Test  url

  6. export CLASSPATH  spa

JAVA_HOME爲jdk的根目錄

PATH爲java工具類路徑(java,javac,rmic等)

CLASSPATH爲java .class文件的存放路徑,使用java命令運行.class文件時即會在該參數配置的路徑下尋找相應文件

 

java RMI的缺點:

1,從代碼中也能夠看到,代碼依賴於ip與端口

2,RMI依賴於Java遠程消息交換協議JRMP(Java Remote Messaging Protocol),該協議爲java定製,要求服務端與客戶端都爲java編寫


  1. [name@name ~]$ vi .bash_profile   

[plain] view plain copy

<EMBED id=ZeroClipboardMovie_12 height=18 name=ZeroClipboardMovie_12 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=12&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. [name@name client]$ java client.HelloClient  

  2. Hello,zx  

同服務器端,/home/name/Test必定要在系統CLASSPATH中

 

PS:

1,客戶端所在服務和服務端所在的服務器網絡必定要通(一開始浪費了不少時間,最後才發現是網絡不通)

2,全部代碼在jdk1.5.0_15,Linux服務器上調試經過

3,若是java命令運行提示找不到類文件,則爲CLASSPATH配置問題

[plain] view plain copy

<EMBED id=ZeroClipboardMovie_11 height=18 name=ZeroClipboardMovie_11 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=11&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. package client;  

  2.   

  3. import java.net.MalformedURLException;  

  4. import java.rmi.Naming;  

  5. import java.rmi.NotBoundException;  

  6. import java.rmi.RemoteException;  

  7.   

  8. import server.Hello;  

  9.   

  10. public class HelloClient {  

  11.     public static void main(String[] args) {  

  12.         try {  

  13.             Hello h = (Hello)Naming.lookup("rmi://192.168.58.164:12312/Hello");  

  14.             System.out.println(h.sayHello("zx"));  

  15.         } catch (MalformedURLException e) {  

  16.             System.out.println("url格式異常");  

  17.         } catch (RemoteException e) {  

  18.             System.out.println("建立對象異常");  

  19.             e.printStackTrace();  

  20.         } catch (NotBoundException e) {  

  21.             System.out.println("對象未綁定");  

  22.         }  

  23.     }  

  24. }  

8,運行客戶端(58.163):

Test

- - client

- - - - HelloClient.class

- - server

- - - - Hello.class

- - - - HelloImpl_Stub.class//服務端生成的存根文件

[plain] view plain copy

<EMBED id=ZeroClipboardMovie_10 height=18 name=ZeroClipboardMovie_10 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=10&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. [name@name ~]$ java server.HelloServer  

  2. HelloServer啓動成功  

固然/home/name/Test必定要在系統CLASSPATH中,不然會報找不到相應的.class文件

7,編寫客戶端代碼

[java] view plain copy

<EMBED id=ZeroClipboardMovie_9 height=18 name=ZeroClipboardMovie_9 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=9&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. package server;  

  2.   

  3. import java.rmi.Naming;  

  4. import java.rmi.registry.LocateRegistry;  

  5.   

  6. public class HelloServer {  

  7.     public static void main(String[] args) {  

  8.         try{  

  9.             Hello h = new HelloImpl();  

  10.               

  11.             //建立並導出接受指定port請求的本地主機上的Registry實例。  

  12.             //LocateRegistry.createRegistry(12312);  

  13.               

  14.             /** Naming 類提供在對象註冊表中存儲和得到遠程對遠程對象引用的方法 

  15.              *  Naming 類的每一個方法均可將某個名稱做爲其一個參數, 

  16.              *  該名稱是使用如下形式的 URL 格式(沒有 scheme 組件)的 java.lang.String: 

  17.              *  //host:port/name 

  18.              *  host:註冊表所在的主機(遠程或本地),省略則默認爲本地主機 

  19.              *  port:是註冊表接受調用的端口號,省略則默認爲1099,RMI註冊表registry使用的著名端口 

  20.              *  name:是未經註冊表解釋的簡單字符串 

  21.              */  

  22.             //Naming.bind("//host:port/name", h);  

  23.             Naming.bind("rmi://192.168.58.164:12312/Hello", h);  

  24.             System.out.println("HelloServer啓動成功");  

  25.         }catch(Exception e){  

  26.             e.printStackTrace();  

  27.         }  

  28.     }  

  29. }  

先建立註冊表,而後才能在註冊表中存儲遠程對象信息

6,運行服務端(58.164):

Test

- - server

- - - - Hello.class

- - - - HelloImpl.class

- - - - HelloServer.class

[plain] view plain copy

<EMBED id=ZeroClipboardMovie_8 height=18 name=ZeroClipboardMovie_8 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=8&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. LocateRegistry.createRegistry(12312);  

5,編寫服務端代碼

[java] view plain copy

<EMBED id=ZeroClipboardMovie_7 height=18 name=ZeroClipboardMovie_7 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=7&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. [name@name jdk]$ jdk1.5.0_15/bin/rmiregistry 12312 &  

  2. [1] 22720  

  3. [name@name jdk]$ ps -ef|grep rmiregistry  

  4. name    22720 13763  0 16:43 pts/3    00:00:00 jdk1.5.0_15/bin/rmiregistry 12312  

  5. name    22737 13763  0 16:43 pts/3    00:00:00 grep rmiregistry  

若是不帶具體端口號,則默認爲1099

方式二:人工建立rmiregistry服務,須要在代碼中添加:

[java] view plain copy

<EMBED id=ZeroClipboardMovie_6 height=18 name=ZeroClipboardMovie_6 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=6&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. [name@name Test]$ rmic -classpath /home/name/Test server.HelloImpl  

 運行成功後將會生成HelloImpl_Stub.class文件

4,啓動RMI註冊服務(jdk1.5.0_15/bin/rmiregistry)

方式一:後臺啓動rmiregistry服務

[plain] view plain copy

<EMBED id=ZeroClipboardMovie_5 height=18 name=ZeroClipboardMovie_5 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=5&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. [name@name Test]$ cd /home/name/Test/  

  2. [name@name Test]$ rmic server.HelloImpl  

方式二:

[plain] view plain copy

<EMBED id=ZeroClipboardMovie_4 height=18 name=ZeroClipboardMovie_4 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=4&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. package server;  

  2.   

  3. import java.rmi.RemoteException;  

  4. import java.rmi.server.UnicastRemoteObject;  

  5.   

  6. public class HelloImpl extends UnicastRemoteObject implements Hello {  

  7.     private static final long serialVersionUID = -271947229644133464L;  

  8.   

  9.     public HelloImpl() throws RemoteException{  

  10.         super();  

  11.     }  

  12.   

  13.     public String sayHello(String name) throws RemoteException {  

  14.         return "Hello,"+name;  

  15.     }  

  16. }  

3,利用java自帶rmic工具生成sutb存根類(jdk1.5.0_15/bin/rmic)

jdk1.2之後的RMI能夠經過反射API能夠直接將請求發送給真實類,因此不須要skeleton類了

sutb存根爲遠程方法類在本地的代理,是在服務端代碼的基礎上生成的,須要HelloImpl.class文件,因爲HelloImpl繼承了Hello接口,故Hello.class文件也是不可少的

Test

- - server

- - - - Hello.class

- - - - HelloImpl.class

方式一:

[plain] view plain copy

<EMBED id=ZeroClipboardMovie_3 height=18 name=ZeroClipboardMovie_3 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=3&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. package server;  

  2.   

  3. import java.rmi.Remote;  

  4. import java.rmi.RemoteException;  

  5.   

  6. public interface Hello extends Remote {  

  7.     public String sayHello(String name) throws RemoteException;  

  8. }  

因爲遠程方法調用的本質依然是網絡通訊,只不過隱藏了底層實現,網絡通訊是常常會出現異常的,因此接口的全部方法都必須拋出RemoteException以說明該方法是有風險的

2,建立遠程方法接口實現類:

UnicastRemoteObject類的構造函數拋出了RemoteException,故其繼承類不能使用默認構造函數,繼承類的構造函數必須也拋出RemoteException

因爲方法參數返回值最終都將在網絡上傳輸,故必須是可序列化的

[java] view plain copy

<EMBED id=ZeroClipboardMovie_2 height=18 name=ZeroClipboardMovie_2 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=2&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

3,服務端輔助對象將客戶端輔助對象發送來的信息解包,找出真正被調用的方法以及該方法所在對象

4,調用真正服務對象上的真正方法,並將結果返回給服務端輔助對象

5,服務端輔助對象將結果打包,發送給客戶端輔助對象

6,客戶端輔助對象將返回值解包,返回給客戶對象

7,客戶對象得到返回值

對於客戶對象來講,步驟2-6是徹底透明的

 

搭建一個RMI服務的過程分爲如下7步;

1,建立遠程方法接口,該接口必須繼承自Remote接口

Remote 接口是一個標識接口,用於標識所包含的方法能夠從非本地虛擬機上調用的接口,Remote接口自己不包含任何方法

[java] view plain copy

<EMBED id=ZeroClipboardMovie_1 height=18 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=1&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

相關文章
相關標籤/搜索