日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java RMI远程方法调用详解

發布時間:2024/4/15 java 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java RMI远程方法调用详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java RMI遠程方法調用詳解

? ? 【尊重原創,轉載請注明出處】http://blog.csdn.net/guyuealian/article/details/51992182一、Java RMI機制: ? ?? ??遠程方法調用RMI(Remote Method Invocation),是允許運行在一個Java虛擬機的對象調用運行在另一個Java虛擬機上的對象的方法。 這兩個虛擬機可以是運行在相同計算機上的不同進程中,也可以是運行在網絡上的不同計算機中。? ? ? ?Java RMI:Java遠程方法調用,即Java RMI(Java Remote Method Invocation)是Java編程語言里,一種用于實現遠程過程調用的應用程序編程接口。它使客戶機上運行的程序可以調用遠程服務器上的對象。遠程方法調用特性使Java編程人員能夠在網絡環境中分布操作。RMI全部的宗旨就是盡可能簡化遠程接口對象的使用。
? ? ? ?而RPC是遠程過程調用(Remote Procedure Call)可以用于一個進程調用另一個進程(很可能在另一個遠程主機上)中的過程,從而提供了過程的分布能力。Java 的 RMI 則在 RPC 的基礎上向前又邁進了一步,即提供分布式對象間的通訊
?(1)RMI框架? ? ? ?【參考資料】? ? ?? ?《Java網絡編程精解》孫衛琴,這本書適合入門學習RMI框架基礎 ??? ? ? ? ?http://wenku.baidu.com/view/90171bd03186bceb19e8bbdc.html?from=search? ? ? ?RMI框架封裝了所有底層通信細節,并且解決了編組、分布式垃圾收集、安全檢查和并發性等通用問題。有了現成的框架,開發人員就只需專注于開發與特定問題領域相關的各種本地對象和遠程對象。

? ? ? 要了解RMI原理,先了解一下Stub和Skeleton兩個概念。
(2)Stub和Skeleton?? ? ?RMI框架采用代理來負責客戶與遠程對象之間通過Socket進行通信的細節。RMI框架為遠程對象分別生成了客戶端代理和服務器端代理。位于客戶端的代理類稱為存根(Stub),位于服務器端的代理類稱為骨架(Skeleton)。

? ? 【相關資料? ? ?《RMI(Remote Method Invocation)初窺門徑》 http://blog.csdn.net/smcwwh/article/details/7080997?? ? ?stub(存根)和skeleton(骨架)在RMI中充當代理角色,在現實開發中主要是用來隱藏系統和網絡的的差異, 這一部分的功能在RMI開發中對程序員是透明的。Stub為客戶端編碼遠程命令并把他們發送到服務器。而Skeleton則是把遠程命令解碼,調用服務端的遠程對象的方法,把結果在編碼發給stub,然后stub再解碼返回調用結果給客戶端。? ? ?RMI遠程過程調用的實現過程如下圖所示:
? ? ?RMI 框架的基本原理大概如下圖,應用了代理模式來封裝了本地存根與真實的遠程對象進行通信的細節
參考資料? ? 《Java RMI 框架(遠程方法調用)》http://haolloyin.blog.51cto.com/1177454/332426 ?? ? 《?java RMI原理詳解》 http://blog.csdn.net/xinghun_4/article/details/45787549

二、Java RMI 簡單示例

? ? 別急,慢慢分析~具體代碼在下面,附例子代碼下載:http://download.csdn.net/detail/guyuealian/9583633大致說來,創建一個RMI應用包括以下步驟:? ? ? (1)創建遠程接口:繼承java.rmi.Remote接口。
? ? ? (2)創建遠程類:實現遠程接口。
? ? ? (3)創建服務器程序:創建遠程對象,通過createRegistry()方法注冊遠程對象。并通過bind或者rebind方法,把遠程對象綁定到指定名稱空間(URL)中。
? ? ? (4)創建客戶程序:通過 lookup()方法查找遠程對象,進行遠程方法調用?
?? ? 下面具體分析每個步驟:
(1)創建遠程接口:繼承java.rmi.Remote接口。
? ? ? ?遠程接口中聲明了可以被客戶程序訪問的遠程方法。RMI規范要求遠程對象所屬的類實現一個遠程接口,并且遠程接口符合以下條件:
? ? ? ?(a)直接或間接繼承java.rmi.Remote接口。
? ? ? ?(b)接口中的所有方法聲明拋出java.rmi.RemoteException。
(2)創建遠程類:實現遠程接口。
? ? ? ??遠程類就是遠程對象所屬的類。RMI規范要求遠程類必須實現一個遠程接口。此外,為了使遠程類的實例變成能為遠程客戶提供服務的遠程對象,可通過以下兩種途徑之一把它導出(export)為遠程對象
? ? ? ?(a)導出為遠程對象的第一種方式:使遠程類實現遠程接口時,同時繼承java.rmi.server.UnicastRemoteObject類,并且遠程類的構造方法必須聲明拋出RemoteException。這是最常用的方式,下面的本例子就采取這種方式。
public class RemoteImpl extends UnicastRemoteObject implements RemoteInterface? ? ? ?(b)導出為遠程對象的第二種方式:如果一個遠程類已經繼承了其他類,無法再繼承UnicastRemoteObject類,那么可以在構造方法中調用UnicastRemoteObject類的靜態exportObject()方法,同樣,遠程類的構造方法也必須聲明拋出RemoteException。public class RemoteImpl?extends OtherClass implements RemoteInterface{private String name;public RemoteImpl?(String name)throws RemoteException{this.name=name;UnicastRemoteObject.exportObject(this,0);} ? ? ? ? 在構造方法RemoteImpl?中調用了UnicastRemoteObject.exportObject(this,0)方法,將自身導出為遠程對象。? ? ? ??exportObject()是UnicastRemoteObject的靜態方法,源碼是: protected UnicastRemoteObject(int port) throws RemoteException{this.port = port;exportObject((Remote) this, port);} public static Remote exportObject(Remote obj, int port)throws RemoteException{return exportObject(obj, new UnicastServerRef(port));}? ? ? ?exportObject(Remote obj, int port),該方法負責把參數obj指定的對象導出為遠程對象,使它具有相應的存根(Stub),并監聽遠程客戶的方法調用請求;參數port指導監聽的端口,如果值為0,表示監聽任意一個匿名端口。
(3)創建服務器程序:創建遠程對象,在rmiregistry注冊表中注冊遠程對象,并綁定到指定的URL中。? ? ? ?RMI采用一種命名服務機制來使得客戶程序可以找到服務器上的一個遠程對象。在JDK的安裝目錄的bin子目錄下有一個rmiregistry.exe程序,它是提供命名服務的注冊表程序。
? ? ? 服務器程序的一大任務就是向rmiregistry注冊表注冊遠程對象。從JDK1.3以上版本開始,RMI的命名服務API被整合到JNDI(Java Naming and Directory Interface,Java名字與目錄接口)中。在JNDI中,javax.naming.Context接口聲明了注冊、查找,以及注銷對象的方法:
? ? 【1】 bind(String name,Object obj):注冊對象,把對象與一個名字name綁定
,這里的name其實就是URL格式。如果該名字已經與其它對象綁定,就會拋出NameAlreadyBoundException。
? ? 【2】rebind(String name,Object obj):注冊對象,把對象與一個名字綁定。如果該名字已經與其它對象綁定,不會拋出NameAlreadyBoundException,而是把當前參數obj指定的對象覆蓋原先的對象。
? ? 【3】 lookup(String name):查找對象,返回與參數name指定的名字所綁定的對象。
? ? 【4】unbind(String name):注銷對象,取消對象與名字的綁定。
? ? ?注冊一個遠程對象remoteObj2?關鍵代碼如下:RemoteInterface remoteObj2 = new RemoteImpl();// 創建遠程對象 Context namingContext = new InitialContext();// 初始化命名內容 LocateRegistry.createRegistry(8892);// 在本地主機上創建和導出注冊表實例,并在指定的端口上接受請求 namingContext.rebind("rmi://localhost:8892/RemoteObj2", remoteObj2);// 注冊對象,即把對象與一個名字綁定。? ? ?但在JDK1.3版本或更低的版本,需要使用java.rmi.Naming來注冊遠程對象,注冊代碼代替如下:RemoteInterface remoteObj = new RemoteImpl(); LocateRegistry.createRegistry(8891); Naming.rebind("rmi://localhost:8891/RemoteObj", remoteObj);(4)創建客戶程序:通過 lookup()方法查找遠程對象,進行遠程方法調用關鍵代碼如下:Context namingContext = new InitialContext();// 初始化命名內容 RemoteInterface RmObj2 = (RemoteInterface) namingContext.lookup("rmi://localhost:8892/RemoteObj2");//獲得遠程對象的存根對象 System.out.println(RmObj2.doSomething());//通過遠程對象,調用doSomething方法? ? ?在JDK1.3版本或更低的版本,如下方式調用;RemoteInterface RmObj = (RemoteInterface) Naming.lookup("rmi://localhost:8891/RemoteObj"); System.out.println(RmObj.doSomething());例子具體代碼:? ?1. 創建遠程接口:繼承java.rmi.Remote接口。
package rmi; import java.rmi.Remote; import java.rmi.RemoteException; //聲明一個遠程接口RemoteInterface,該接口必須繼承Remote接口 //接口中需要被遠程調用的方法,必須拋出RemoteException異常 public interface RemoteInterface extends Remote {// 聲明一個doSomething方法public String doSomething() throws RemoteException;// 聲明一個計算方法Calculatepublic int Calculate(int num1, int num2) throws RemoteException; }? ? ? ?在Java中,只要一個類extends了java.rmi.Remote接口,即可成為存在于服務器端的遠程對象, 供客戶端訪問并提供一定的服務。JavaDoc描述:Remote 接口用于標識其方法可以從非本地虛擬機上調用的接口。任何遠程對象都必須直接或間接實現此接口。只有在“遠程接口” ?(擴展 java.rmi.Remote 的接口)中指定的這些方法才可被遠程調用。注意:接口中需要被遠程調用的方法,必須拋出RemoteException異常。? ? ? 2. 創建遠程類:實現遠程接口package rmi; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; //實現遠程接口RemoteInterface,并繼承UnicastRemoteObject //注意RemoteObject這個類,實現了Serializable, Remote這兩個接口 public class RemoteImpl extends UnicastRemoteObject implements RemoteInterface {// 這個實現必須有一個顯式的構造函數,并且要拋出一個RemoteException異常public RemoteImpl() throws RemoteException {}// 實現doSomething方法public String doSomething() throws RemoteException {return "OK ,You can do......";}// 實現Calculate方法,返回計算結果public int Calculate(int num1, int num2) throws RemoteException {return (num1 + num2);} }? ? ? 遠程對象必須實現java.rmi.server.UniCastRemoteObject類,該類的構造函數中將生成stub和skeleton,?這樣才能保證客戶端訪問獲得遠程對象時,該遠程對象將會把自身的一個拷貝以Socket的形式傳輸給客戶端,此時客戶端所獲得的這個拷貝稱為Stub(存根),?而服務器端本身已存在的遠程對象則稱之為Skeleton(骨架)其實此時的存根是客戶端的一個代理,用于與服務器端的通信,??而骨架也可認為是服務器端的一個代理,用于接收客戶端的請求之后調用遠程方法來響應客戶端的請求。? ? ?3.創建服務器程序:在rmiregistry注冊表中注冊遠程對象,向客戶端提供遠程對象服務 ?
package rmi2; import javax.naming.Context; import javax.naming.InitialContext;import rmi.RemoteInterface;public class ClientTest {public static void main(String args[]) {try {Context namingContext = new InitialContext();// 初始化命名內容RemoteInterface RmObj2 = (RemoteInterface) namingContext.lookup("rmi://localhost:8892/RemoteObj2");//獲得遠程對象的存根對象System.out.println(RmObj2.doSomething());//通過遠程對象,調用doSomething方法System.out.println("遠程服務器計算結果為:" + RmObj2.Calculate(90, 2));} catch (Exception e) {}} }? ?在JDK1.3版本或更低的版本,如下方式注冊;package rmi; import java.net.MalformedURLException; import java.rmi.AlreadyBoundException; import java.rmi.Naming; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; //在JDK1.3版本或更低的版本,需要使用java.rmi.Naming來注冊遠程對象 //創建RMI注冊表,啟動RMI服務,并將遠程對象注冊到RMI注冊表中。 public class RMIServer {public static void main(String args[])throws java.rmi.AlreadyBoundException {try {// 創建一個遠程對象RemoteObj,實質上隱含了是生成stub和skeleton,并返回stub代理引用RemoteInterface remoteObj = new RemoteImpl();// 本地創建并啟動RMI Service,被創建的Registry服務將在指定的端口,偵聽請求// Java默認端口是1099,缺少注冊表創建,則無法綁定對象到遠程注冊表上LocateRegistry.createRegistry(8891);// 把遠程對象注冊到RMI注冊服務器上,并命名為RemoteObj(名字可自定義,客戶端要對應)// 綁定的URL標準格式為:rmi://host:port/name(其中協議名可以省略,下面兩種寫法都是正確的)Naming.rebind("rmi://localhost:8891/RemoteObj", remoteObj);// 將stub代理綁定到Registry服務的URL上// Naming.bind("//localhost:8880/RemoteObj",remoteObj);System.out.println(">>>>>INFO:遠程IHello對象綁定成功!");} catch (RemoteException e) {System.out.println("創建遠程對象發生異常!");e.printStackTrace();} catch (MalformedURLException e) {System.out.println("發生URL畸形異常!");e.printStackTrace();}} }? ? ?RMIServer類主要實現注冊遠程對象,并向客戶端提供遠程對象服務。遠程對象是在遠程服務上創建的,你無法確切地知道遠程服務器上的對象的名稱 。但是,將遠程對象注冊到RMI Service之后,客戶端就可以通過RMI Service請求到該遠程服務對象的stub了,利用stub代理就可以訪問遠程服務對象了 。
? ? ? 4. 客戶端代碼? ? ?Server端的代碼已經全部寫完,這時把服務器的接口RemoteInterface打包成jar,以便在Client端的項目使用。? ? ?項目-->右鍵-->導出-->jar->選擇RemoteInterface.java-->finish;關于客戶端如何導入jar包,請看這里:http://jingyan.baidu.com/article/ca41422fc76c4a1eae99ed9f.html

package rmi2; import javax.naming.Context; import javax.naming.InitialContext;import rmi.RemoteInterface; public class ClientTest {public static void main(String args[]) {try {Context namingContext = new InitialContext();// 初始化命名內容RemoteInterface RmObj2 = (RemoteInterface) namingContext.lookup("rmi://localhost:8892/RemoteObj2");//獲得遠程對象的存根對象System.out.println(RmObj2.doSomething());//通過遠程對象,調用doSomething方法System.out.println("遠程服務器計算結果為:" + RmObj2.Calculate(90, 2));} catch (Exception e) {}} }在JDK1.3版本或更低的版本,如下方式調用
import java.net.MalformedURLException; import java.rmi.Naming; import java.rmi.NotBoundException; import java.rmi.RemoteException;public class ClientTest {public static void main(String args[]) {try {// 在RMI服務注冊表中查找名稱為RemoteObj的對象,并調用其上的方法// 客戶端通過命名服務Naming獲得指向遠程對象的遠程引用RemoteInterface RmObj = (RemoteInterface) Naming.lookup("rmi://localhost:8881/RemoteObj");System.out.println(RmObj.doSomething());System.out.println("遠程服務器計算結果為:" + RmObj.Calculate(1, 2));} catch (NotBoundException e) {e.printStackTrace();} catch (MalformedURLException e) {e.printStackTrace();} catch (RemoteException e) {e.printStackTrace();}} }輸出結果:OK ,You can do...... 遠程服務器計算結果為:92例子代碼下載:http://download.csdn.net/detail/guyuealian/9583633




如果你覺得該帖子幫到你,還望貴人多多支持,鄙人會再接再厲,繼續努力的~

超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

總結

以上是生活随笔為你收集整理的Java RMI远程方法调用详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。