本篇用實(shí)例來說明采用Java進(jìn)行RMI遠(yuǎn)程方法調(diào)用的實(shí)現(xiàn)方法,從而為分布應(yīng)用軟件的開發(fā)者提供參考和幫助。
Internet/Intranet的飛速發(fā)展使得Web應(yīng)用日益廣泛而復(fù)雜,Web早已不僅僅是超媒體信息的瀏覽工具,它正逐步發(fā)展成為分布異構(gòu)環(huán)境中企業(yè)應(yīng)用的通用前端和事務(wù)處理的展現(xiàn)窗口。在分布式環(huán)境異構(gòu)中,各種機(jī)器所采用的操作系統(tǒng)、網(wǎng)絡(luò)通信協(xié)議和應(yīng)用軟件千差萬別,要實(shí)現(xiàn)信息共享和軟件資源的整合十分困難,然而一個健壯的分布式計(jì)算框架能為可移植的分布式應(yīng)用軟件開發(fā)帶來巨大的便利和好處。
分布式對象技術(shù)主要是在分布式異構(gòu)環(huán)境下建立應(yīng)用系統(tǒng)框架和對象構(gòu)件。在應(yīng)用系統(tǒng)框架的支撐下,開發(fā)者可以將軟件功能封裝為更易管理和使用的對象,這些對象可以跨越不同的軟、硬件平臺進(jìn)行互操作。目前,分布式互操作標(biāo)準(zhǔn)主要有Microsoft的COM/DCOM標(biāo)準(zhǔn)、Sun公司的Java RMI標(biāo)準(zhǔn)和OMG組織的CORBA標(biāo)準(zhǔn)。
Java RMI調(diào)用實(shí)例
Java RMI簡介
遠(yuǎn)程方法調(diào)用(RMI,Remote Method Invocation)是jdk1.1中引入的分布式對象軟件包,它的出現(xiàn)大大簡化了分布異構(gòu)環(huán)境中Java應(yīng)用之間的通信。
要使用RMI,必須構(gòu)建四個主要的類:遠(yuǎn)程對象的本地接口、遠(yuǎn)程對象實(shí)現(xiàn)、RMI客戶機(jī)和RMI服務(wù)器。RMI服務(wù)器生成遠(yuǎn)程對象實(shí)現(xiàn)的一個實(shí)例,并用一個專有的URL注冊。RMI客戶機(jī)在遠(yuǎn)程RMI服務(wù)器上查找服務(wù)對象,并將它轉(zhuǎn)換成本地接口類型,然后像對待一個本地對象一樣使用它。
下面是一個簡單的RMI實(shí)例,RMI客戶機(jī)通過RMI服務(wù)器提供的方法實(shí)現(xiàn)對兩個雙精度浮點(diǎn)數(shù)的加減運(yùn)算。例子雖然很簡單,但掌握了Java RMI調(diào)用的基本原理和方法,在實(shí)現(xiàn)復(fù)雜應(yīng)用時(shí),我們需要做的也只是完善遠(yuǎn)程對象的實(shí)現(xiàn)類而已。
RMI實(shí)例分析
1.遠(yuǎn)程對象的本地接口聲明(RMIOperate.java)
該類僅僅是一個接口聲明,RMI客戶機(jī)可以直接使用它,RMI服務(wù)器必須通過一個遠(yuǎn)程對象來實(shí)現(xiàn)它,并用某個專有的URL注冊它的一個實(shí)例。
具體代碼如下:
package wf.rmi; //包名
import java.rmi.*; //導(dǎo)入類包
/*RMI本地接口必須從Remote接口派生*/
public interface RMIOperate extends Remote
{
/*接口中的具體方法聲明,注意必須聲明拋出RemoteException*/
public double add(double x, double y) throws RemoteException;
//輸入兩個浮點(diǎn)數(shù),返回其和
public double minus(double x, double y) throws RemoteException;
//輸入兩個浮點(diǎn)數(shù),返回其差
}
2.遠(yuǎn)程對象實(shí)現(xiàn)類(OperateImpl.java)
這個類應(yīng)實(shí)現(xiàn)RMI客戶機(jī)調(diào)用的遠(yuǎn)程服務(wù)對象的本地接口,它必須從UnicastRemoteObject繼承,構(gòu)造函數(shù)應(yīng)拋出RemoteException異常。
具體代碼如下:
package wf.rmi; //包名
//導(dǎo)入需要的類包
import java.rmi.*;
import wf.rmi.RMIOperate;
import java.rmi.server.UnicastRemoteObject;
public class OperateImpl extends UnicastRemoteObject implements RMIOperate
{
/*構(gòu)造函數(shù)*/
public OperateImpl() throws RemoteException
{
}
/*實(shí)現(xiàn)本地接口中聲明的add方法*/
public double add(double x, double y) throws RemoteException
{
double z = x + y;
return z;
}
/*實(shí)現(xiàn)本地接口中聲明的minus方法*/
public double minus(double x, double y) throws RemoteException
{
double z = x - y;
return z;
}
}
3.RMI服務(wù)器類(RMIServer.java)
該類創(chuàng)建遠(yuǎn)程對象實(shí)現(xiàn)類OperateImpl的一個實(shí)例,然后通過一個專有的URL來注冊它。所謂注冊就是通過Java.rmi.Naming.bind()方法或Java.rmi.Naming.rebind()方法,將OperateImpl實(shí)例綁定到指定的URL上。
具體實(shí)現(xiàn)代碼如下:
package wf.rmi; //包名
//導(dǎo)入需要的類包
import java.rmi.Naming;
import wf.rmi.OperateImpl;
public class RMIServer
{
public static void main(String[] args)
{
try
{
//創(chuàng)建遠(yuǎn)程對象的實(shí)現(xiàn)實(shí)例
OperateImpl operObj = new OperateImpl();
//提示信息
System.out.println("RMI Server Starting...");
//將實(shí)例注冊到專有的URL
Naming.rebind("rmi:///RMIOperate", operObj);
//等待RMI客戶機(jī)調(diào)用的提示信息
System.out.println("Waiting RMI Client Invoke...");
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
4.RMI客戶機(jī)類(RMIClient.java)
RMI客戶使用java.rmi.Naming.lookup()方法,在指定的遠(yuǎn)程主機(jī)上查找RMI服務(wù)對象,若找到就把它轉(zhuǎn)換成本地接口RMIOperate類型。它與CORBA不同之處在于RMI客戶機(jī)必須知道提供RMI服務(wù)主機(jī)的URL,這個URL可以通過rmi://host/path或rmi://host:port/path來指定,如果省略端口號,就默認(rèn)使用1099。Java.rmi.Naming.lookup()方法可能產(chǎn)生三個異常:Java.rmi.RemoteException、Java.rmi.NotBoundException、java.net. MalformedURLException,三個異常都需要捕獲。
下面是詳細(xì)代碼:
package wf.rmi; //包名
//導(dǎo)入需要的類包
import java.rmi.*;
import java.net.*;
import java.io.*;
public class RMIClient
{
public static void main(String[] args)
{
try
{
BufferedReader readIn = new BufferedReader(new
InputStreamReader(System.in));
String host = "localhost"; //默認(rèn)為本地主機(jī)
//帶輸入?yún)?shù)時(shí),將host設(shè)置為指定主機(jī)
if (args.length > 0)
host = args[0];
//根據(jù)指定的URL定位遠(yuǎn)程實(shí)現(xiàn)對象
RMIOperate rmiObj = (RMIOperate)Naming.lookup("rmi://" + host +
"/RMIOperate"); //提示輸入運(yùn)算參數(shù)1
System.out.println("Please Input Data1: ");
String str1 = readIn.readLine(); //讀取輸入?yún)?shù)1
double x = 0;
try
{
x = Double.parseDouble(str1); //分析輸入?yún)?shù)1,轉(zhuǎn)換為double類型
}
catch(NumberFormatException nfe)
{
x = 0; //如果轉(zhuǎn)換異常,則重置x為0
}
//提示輸入運(yùn)算參數(shù)2
System.out.println("Please Input Data2: ");
String str2 = readIn.readLine();//讀取輸入?yún)?shù)2
double y = 0;
try
{
y = Double.parseDouble(str2); //分析輸入?yún)?shù)2,轉(zhuǎn)換為double類型
}
catch(NumberFormatException nfe)
{
y = 0; //如果轉(zhuǎn)換異常,則重置y為0
}
//調(diào)用遠(yuǎn)程對象的本地接口方法,實(shí)現(xiàn)輸入?yún)?shù)的加、減運(yùn)算,并輸出結(jié)果
System.out.println("Data1 Add Data2 Result is: " + rmiObj.add(x, y));
System.out.println("Data1 minus Data2 Result is: " +
rmiObj.minus(x, y));
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
RMI Server/Client的編譯與運(yùn)行
(1).編譯所有的源代碼(如圖1)

圖1
(2).生成客戶端存根和服務(wù)器框架(如圖2)

圖2
這將構(gòu)造OperateImpl_Stub.class和OperateImpl_Skel.class。這時(shí)可將所有的Class文件打包成jar,并將其分別置于RMI客戶機(jī)和RMI服務(wù)器的ClassPath中(如圖3):

圖3
當(dāng)然,也可以只將RMIOperate.class、RMIClient.class和OperateImpl_Stub.class復(fù)制到RMI客戶機(jī),將RMIOperate.class、OperateImpl.class 、RMIServer.class和OperateImpl_Skel.class復(fù)制到RMI服務(wù)器。
(3).啟動RMI注冊(如圖4)

圖4
(4).運(yùn)行和調(diào)用
● 在服務(wù)器上執(zhí)行RMIServer(如圖5)

圖5
● 在本地客戶機(jī)上運(yùn)行RMIClient(如圖6)

圖6
● 在遠(yuǎn)程客戶機(jī)上運(yùn)行RMIClient(須指明RMI服務(wù)器主機(jī)名或IP地址,如圖7)

圖7
至此,RMI調(diào)用完成。
??????? 摘自:
http://youngyj1982.bokee.com/
posted on 2006-12-31 14:18
壞男孩 閱讀(1044)
評論(0) 編輯 收藏 所屬分類:
java命令學(xué)習(xí)