使用RMI和CORBA進(jìn)行分布式j(luò)ava程序設(shè)計(jì)
(
by huihoo.com lizhi)
分布式程序設(shè)計(jì)討論>>> 英文原文:http://developer.java.sun.com/developer/technicalArticles/RMI/rmi_corba/
RMI和corba是兩種最重要和使用最廣泛的分布式對(duì)象系統(tǒng)。 每種都有它的長處和短處。這兩種系統(tǒng)都在從電子商務(wù)到衛(wèi)生保健等不同的行業(yè)成功的使用。在項(xiàng)目中使用這兩種分布機(jī)制中的任何一種都是一項(xiàng)很困難的任務(wù)。本文介紹了RMI和corba的機(jī)理和最主要的是顯示了如何開發(fā)一個(gè)有用的程序(一個(gè)從遠(yuǎn)程站點(diǎn)下載文件的程序)。于是有以下內(nèi)容:
- 一個(gè)分布式系統(tǒng)的簡介
- 一個(gè)RMI和corba的簡介
- 讓你體驗(yàn)開發(fā)一個(gè)RMI和corba程序的滋味。
- 說明如何使用RMI和corba從遠(yuǎn)程機(jī)器交換文件
- 提供一個(gè)RMI和Corba的比較。
客戶/服務(wù)端模式
客戶/服務(wù)模式是一個(gè)分布式計(jì)算應(yīng)用。它通過使用一個(gè)應(yīng)用程序(客戶)和另一個(gè)程序(服務(wù)端)交換數(shù)據(jù)。在這樣的一個(gè)例子里面客戶端和服務(wù)端一般使用同樣的語言來編寫,使用相同的協(xié)議來相互通信。
在客戶/服務(wù)模式應(yīng)用到各種各樣的地方的過程中,使用低層次的socket來開發(fā)是很典型的。使用socket來開發(fā)客戶/服務(wù)端模式意味著我們必須自己設(shè)計(jì)一種協(xié)議,該協(xié)議包含客戶端和服務(wù)端都統(tǒng)一的命令集 ,使得客戶端和服務(wù)端能夠通過這個(gè)協(xié)議來通信。例如:HTTP協(xié)議提供了一個(gè)get的方法。所有的web服務(wù)器軟件都集成了該功能,而所有的瀏覽器軟件都能夠使用該功能來獲得資料。
分布式對(duì)象模式
分布式對(duì)象系統(tǒng)是一個(gè)對(duì)象集合,通過定義很完善的統(tǒng)一的接口來分隔開的要求服務(wù)(客戶端)和功能服務(wù)(服務(wù)端)。換句話說客戶端和公共服務(wù)的提供分隔開,這些服務(wù)包括數(shù)據(jù)表現(xiàn)和執(zhí)行的代碼。這是一個(gè)分辨分布式對(duì)象模式和客戶/服務(wù)模式的主要不同。
在分布式對(duì)象模式里,客戶端發(fā)送一個(gè)消息到一個(gè)對(duì)象,由這個(gè)對(duì)象解釋這個(gè)消息然后決定應(yīng)該由什么服務(wù)來完成。這個(gè)服務(wù),方法或選擇的完成可能是被一個(gè)對(duì)象或是被一個(gè)broker。RMI和corba就是這種模式的例子。
RMI
RMI是一個(gè)分布式對(duì)象模式。它使得使用java開發(fā)分布式程序更加容易。由于不需要設(shè)計(jì)協(xié)議(這基本是一個(gè)錯(cuò)誤的任務(wù)) 使得使用RMI開發(fā)分布式程序比使用socket更加容易。在RMI里面設(shè)計(jì)者就象在調(diào)用一個(gè)本地的類的方法一樣,而實(shí)際上是在調(diào)用的時(shí)候相應(yīng)的參數(shù)被發(fā)送到遠(yuǎn)端的對(duì)象和然后被解釋。最后結(jié)果返回給調(diào)用者。
一個(gè) RMI應(yīng)用的流程
使用 RMI開發(fā)一個(gè)分布式應(yīng)用包括如下幾個(gè)步驟
1)定義一個(gè)遠(yuǎn)端的接口
2)實(shí)現(xiàn)這個(gè)遠(yuǎn)端的接口
3)開發(fā)一個(gè)服務(wù)端
4)開發(fā)一個(gè)客戶端
5)生成Stubs 和Skeletons,運(yùn)行RMI注冊(cè)器,服務(wù)端 和客戶端
我們現(xiàn)在通過開發(fā)一個(gè)文件交換程序來解釋這些步驟
例子:文件交換程序
這個(gè)應(yīng)用允許客戶端從服務(wù)端交換(或下載)所有類型的文件。第一步是定義一個(gè)遠(yuǎn)程的接口,這個(gè)接口指定了的簽名方法將被服務(wù)端提供和被客戶端調(diào)用。
定義一個(gè)遠(yuǎn)程接口
這個(gè)程序的遠(yuǎn)程接口在代碼例子1中列出,接口FileInterface提供一個(gè)downloadFile這個(gè)帶一個(gè)字符竄(文件名)變量的的方法,然后返回以一個(gè)字符竄序列的形式的相應(yīng)文件數(shù)據(jù)。
代碼例子1: FileInterface.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface FileInterface extends Remote {
public byte[] downloadFile(String fileName) throws
RemoteException;
}
注意接口FileInterface的如下特征:
- 它必須定義成public,這是為了讓客戶端能夠通過調(diào)用遠(yuǎn)程接口來間接調(diào)用遠(yuǎn)程的對(duì)象。
- 必須使用從Remote接口擴(kuò)展過來,這是創(chuàng)建一個(gè)遠(yuǎn)程的對(duì)象的需要。
- 每個(gè)接口方法中必須拋出java.rmi.RemoteException錯(cuò)誤。
實(shí)現(xiàn)遠(yuǎn)程的接口
下一步是實(shí)現(xiàn)遠(yuǎn)程的接口FileInterface。實(shí)現(xiàn)的例子在代碼例子 2中列出。類FileImpl從UnicastRemoteObject擴(kuò)展來。這顯示出FileImpl類是用來創(chuàng)建一個(gè)單獨(dú)的,不能復(fù)制的,遠(yuǎn)程的對(duì)象,
這個(gè)對(duì)象使用RMI 的默認(rèn)的基于TCP的通信方式。
代碼例子 2: FileImpl.java
import java.io.*;
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
public class FileImpl extends UnicastRemoteObject
implements FileInterface {
private String name;
public FileImpl(String s) throws RemoteException{
super();
name = s;
}
public byte[] downloadFile(String fileName){
try {
File file = new File(fileName);
byte buffer[] = new byte[(int)file.length()];
BufferedInputStream input = new
BufferedInputStream(new FileInputStream(fileName));
input.read(buffer,0,buffer.length);
input.close();
return(buffer);
} catch(Exception e){
System.out.println("FileImpl: "+e.getMessage());
e.printStackTrace();
return(null);
}
}
}
編寫服務(wù)端
第3步是實(shí)現(xiàn)一個(gè)服務(wù)端。有3件事服務(wù)端需要去做:
1)創(chuàng)建一個(gè)RMISecurityManager實(shí)例,然后安裝它。
2)創(chuàng)建一個(gè)遠(yuǎn)程對(duì)象的實(shí)例(這個(gè)例子中是FileImpl )
3)使用RMI注冊(cè)工具來注冊(cè)這個(gè)對(duì)象。
代碼例子 3中顯示了如何操作的。
代碼例子 3: FileServer.java
import java.io.*;
import java.rmi.*;
public class FileServer {
public static void main(String argv[]) {
if(System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
FileInterface fi = new FileImpl("FileServer");
Naming.rebind("http://127.0.0.1/FileServer", fi);
} catch(Exception e) {
System.out.println("FileServer: "+e.getMessage());
e.printStackTrace();
}
}
}
聲明Naming.rebind("http://127.0.0.1/FileServer", fi) 中假定了RMI注冊(cè)工具(RMI registry )使用1099端口并在運(yùn)行中。如果你在其他的端口運(yùn)行了RMI注冊(cè)工具,你必須在這個(gè)聲明中定義。例如如果RMI注冊(cè)工具在4500端口運(yùn)行。你的聲明要變成
Naming.rebind("http://127.0.0.1:4500/FileServer", fi)
另外我們已經(jīng)同時(shí)假定了我們的服務(wù)端和RMI注冊(cè)工具是運(yùn)行在同一臺(tái)機(jī)器上的。如果不是的話你要修改rebind方法中的地址。
編寫客戶端 下一步是編寫一個(gè)客戶端,客戶端可以遠(yuǎn)程調(diào)用遠(yuǎn)程接口(FileInterface)中說明的任何一個(gè)方法。無論如何實(shí)現(xiàn),客戶端必須先從RMI注冊(cè)工具獲得一個(gè)遠(yuǎn)程對(duì)象的引用。當(dāng)引用獲得后方法downloadFile 被調(diào)用。客戶端的例子在代碼例子4中,執(zhí)行過程中客戶端從命令行中獲得兩個(gè)參數(shù),第一個(gè)是要下載的文件名,第二個(gè)是要下載的機(jī)器的地址。對(duì)應(yīng)地址的機(jī)器上運(yùn)行服務(wù)端。
代碼例子 4: FileClient.java
import java.io.*;
import java.rmi.*;
public class FileClient{
public static void main(String argv[]) {
if(argv.length != 2) {
System.out.println("Usage: java FileClient fileName machineName");
System.exit(0);
}
try {
String name = "http://" + argv[1] + "/FileServer";
FileInterface fi = (FileInterface) Naming.lookup(name);
byte[] filedata = fi.downloadFile(argv[0]);
File file = new File(argv[0]);
BufferedOutputStream output = new
BufferedOutputStream(new FileOutputStream(file.getName()));
output.write(filedata,0,filedata.length);
output.flush();
output.close();
} catch(Exception e) {
System.err.println("FileServer exception: "+ e.getMessage());
e.printStackTrace();
}
}
}
運(yùn)行程序
為了運(yùn)行程序我們必須生成stubs 和 skeletons,為了生成stubs 和 skeletons,我們使用rmic來編譯:
prompt> rmic FileImpl
將會(huì)生成兩個(gè)文件FileImpl_Stub.class和 FileImpl_Skel.class. stub是客戶端的代理而skeleton是服務(wù)端的框架。
下一步是編譯服務(wù)端和客戶端。使用javac來編譯。注意如果服務(wù)端和客戶端在兩個(gè)不同的機(jī)器,為了編譯客戶端你必須復(fù)制一個(gè)FileInterface接口。
最后,到你運(yùn)行RMI注冊(cè)工具和運(yùn)行服務(wù)端和客戶端的時(shí)候了。使用rmiregistry 或者 start rmiregistry 命令來運(yùn)行RMI注冊(cè)工具到window系統(tǒng)的默認(rèn)的端口上,要運(yùn)行RMI注冊(cè)工具在一個(gè)其他的端口的話使用端口參數(shù)。
prompt> rmiregistry portNumber
RMI注冊(cè)工具運(yùn)行之后,你要運(yùn)行服務(wù)FileServer,因?yàn)镽MI的安全機(jī)制將在服務(wù)端發(fā)生作用,所以你必須增加一條安全策略。以下是對(duì)應(yīng)安全策略的例子
grant {
permission java.security.AllPermission "", "";
};
注意:這是一條最簡單的安全策略,它允許任何人做任何事,對(duì)于你的更加關(guān)鍵性的應(yīng)用,你必須指定更加詳細(xì)安全策略。
現(xiàn)在為了運(yùn)行服務(wù)端,你需要除客戶類(FileClient.class)之外的所有的類文件。確認(rèn)安全策略在policy.txt文件之后,使用如下命令來運(yùn)行服務(wù)器。
prompt> java -Djava.security.policy=policy.txt FileServer
為了在其他的機(jī)器運(yùn)行客戶端程序你需要一個(gè)遠(yuǎn)程接口(FileInterface.class) 和一個(gè)stub(FileImpl_Stub.class)。 使用如下命令運(yùn)行客戶端
prompt> java FileClient fileName machineName
這里fileName是要下載的文件名,machineName 是要下載的文件所在的機(jī)器(也是服務(wù)端所在的機(jī)器)
如果所有都可以了話,當(dāng)客戶端運(yùn)行后,這個(gè)文件將下載到本地。
我們提到如果要運(yùn)行客戶端,我們需要遠(yuǎn)程接口和stub,另外一個(gè)更好的方法是使用RMI動(dòng)態(tài)類加載,這個(gè)方法使得你不必要復(fù)制遠(yuǎn)程接口和stub。取而代之的是,它們能夠在一個(gè)共同的目錄里面被客戶端和服務(wù)端查找到。為了做到這個(gè)你必須使用以下命令來運(yùn)行客戶端。
使用如下命令
java -Djava.rmi.server.codebase=http://hostname/locationOfClasses FileClient fileName machineName.
更多的信息看這里Dynamic Code Loading using RMI.
CORBA
CORBA(The Common Object Request Broker Architecture:通用對(duì)象請(qǐng)求代理結(jié)構(gòu))是對(duì)象管理組織(ORG)在分布式對(duì)象項(xiàng)目方面資助的一個(gè)工業(yè)標(biāo)準(zhǔn)。CORBA只是一個(gè)標(biāo)準(zhǔn),一個(gè)CORBA服務(wù)以O(shè)RB(Object Request Broker對(duì)象要求代理)的形式來運(yùn)行,市場上有很多可用的CORBA ORB服務(wù)軟件例如VisiBroker, ORBIX, 和其他一些ORB軟件。JavaIDL 是其中的一個(gè),它是jdk1.3或jdk1.3以上版本的一個(gè)核心開發(fā)包。
CORBA的設(shè)計(jì)是獨(dú)立于平臺(tái)和語言的,因此CORBA可以在任何平臺(tái)上運(yùn)行,可以定位在網(wǎng)絡(luò)的任何地方,能夠使用任何有IDL(Interface Definition Language )映射的語言。
和RMI相類似,CORBA對(duì)象使用接口來描述,然而接口在CORBA中是定義在IDL中的。IDL很類似于C++,但是IDL不是編程語言,更多的關(guān)于CORBA的介紹在這里有Distributed Programming with Java: Chapter 11 (Overview of CORBA).
CROBA程序的編寫過程
開發(fā)CORBA有很多復(fù)雜的步驟,如下
1.定義一個(gè)IDL
2.把IDL接口映射到j(luò)ava
3.開發(fā)server端
4.開發(fā)client端
5.運(yùn)行名字服務(wù),服務(wù)端 和客戶端
我們現(xiàn)在一步步的解釋一個(gè)基corba的文件交換程序的開發(fā),這有點(diǎn)類似于我們上面講的RMI程序的開發(fā),我們這里使用JavaIDL(一個(gè)jdk1.3的核心開發(fā)包).
定義接口
當(dāng)你定義一個(gè)corba的接口時(shí),考慮一下服務(wù)要支持的操作,在這個(gè)程序里面客戶端將包含一個(gè)下載文件的方法。代碼例子5顯示了一個(gè)FileInterface接口,Data是一個(gè)用typedef關(guān)鍵字引入的新的類型描述。sequence 在IDL中除了不能定義固定大小外其他都類似于數(shù)組,octet是一個(gè)8字節(jié)的量,相當(dāng)于java中的byte。downloadFile 方法中的參數(shù)是一個(gè)string類型并被定義成in 類型。IDL定義了3中傳輸模式:in(用來接收客戶端到服務(wù)端的輸入),out(用來接收服務(wù)端到客戶端的輸出)和inout(同時(shí)用來輸入和輸出)。
代碼例子 5: FileInterface.idl
interface FileInterface {
typedef sequence<octet> Data;
Data downloadFile(in string fileName);
};
一旦你定義了一個(gè)IDL接口,你就要開始編譯它。JDK1.3+包含了一個(gè)idlj 編譯器,它可以用來映射IDL到j(luò)ava的聲明。
idlj 可以通過不同的命令產(chǎn)生不同的輸出如客戶端的stubs,服務(wù)端的skeletons。
-f<side> 參數(shù)用來指定產(chǎn)生什么。side是如下的client, server, 或 all 參數(shù)分別用來表示客戶端的stubs 和服務(wù)端的 skeletons。在這個(gè)例子里由于服務(wù)端和客戶端在兩個(gè)不同的機(jī)器上,所以我們?cè)诳蛻舳松鲜褂?fclient 在服務(wù)端上使用-fserver 。
現(xiàn)在讓我們編譯FileInterface.idl 來產(chǎn)生服務(wù)端的skeletons,使用如下命令
prompt> idlj -fserver FileInterface.idl
執(zhí)行接口
現(xiàn)在我們提供一個(gè)對(duì)downloadFile方法的執(zhí)行。這個(gè)執(zhí)行就像一個(gè)仆人,你可以從例子6中看出 FileServant 類從_FileInterfaceImplBase 類擴(kuò)展過來。從這個(gè)類可以看出這個(gè)仆人是一個(gè)corba對(duì)象
例子6代碼: FileServant.java
import java.io.*;
public class FileServant extends _FileInterfaceImplBase {
public byte[] downloadFile(String fileName){
File file = new File(fileName);
byte buffer[] = new byte[(int)file.length()];
try {
BufferedInputStream input = new
BufferedInputStream(new FileInputStream(fileName));
input.read(buffer,0,buffer.length);
input.close();
} catch(Exception e) {
System.out.println("FileServant Error: "+e.getMessage());
e.printStackTrace();
}
return(buffer);
}
}
開發(fā)服務(wù)端
下一步是編寫corba服務(wù)端。在例子7中實(shí)現(xiàn)了一個(gè)corba服務(wù)端的類 FileServer。它通過以下的步驟來實(shí)現(xiàn)。
1)定義一個(gè)orb
2)創(chuàng)建一個(gè)FileServant對(duì)象
3)登記到corba命名服務(wù)中(COS Naming)
4)打印狀態(tài)消息
5)等待客戶端請(qǐng)求
例子7代碼: FileServer.java
import java.io.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
public class FileServer {
public static void main(String args[]) {
try{
// create and initialize the ORB
ORB orb = ORB.init(args, null);
// create the servant and register it with the ORB
FileServant fileRef = new FileServant();
orb.connect(fileRef);
// get the root naming context
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
NamingContext ncRef = NamingContextHelper.narrow(objRef);
// Bind the object reference in naming
NameComponent nc = new NameComponent("FileTransfer", " ");
NameComponent path[] = {nc};
ncRef.rebind(path, fileRef);
System.out.println("Server started....");
// Wait for invocations from clients
java.lang.Object sync = new java.lang.Object();
synchronized(sync){
sync.wait();
}
} catch(Exception e) {
System.err.println("ERROR: " + e.getMessage());
e.printStackTrace(System.out);
}
}
}
一旦FileServer 獲得一個(gè)orb, 它能夠登記corba服務(wù)。它使用由omg建議的由Java IDL 實(shí)現(xiàn)的corba名字服務(wù)(COS Naming Service )來登記。它是目錄服務(wù)中從根節(jié)點(diǎn)開始的一個(gè)目錄節(jié)點(diǎn)。這是一個(gè)普通的corba對(duì)象。可以當(dāng)成NamingContext對(duì)象來使用。它必須能夠被narrowed down (換句話說是分級(jí)(casted))
到相應(yīng)的類型。這是使用一個(gè)聲明來實(shí)現(xiàn)的。
NamingContext ncRef = NamingContextHelper.narrow(objRef);
ncRef對(duì)象現(xiàn)在是org.omg.CosNaming.NamingContext對(duì)象。你可以使用它來登記一個(gè)corba服務(wù)。 rebind 調(diào)用方法可以實(shí)現(xiàn)。
開發(fā)客戶端
下一步是開發(fā)一個(gè)客戶端,在例子8里面實(shí)現(xiàn)了,一旦得到了一個(gè)到名字服務(wù)的引用,它就能夠被用來進(jìn)入名字服務(wù)和能夠用來查找一些服務(wù)(例如這里查找的是FileTransfer 服務(wù))當(dāng)FileTransfer 服務(wù)被找到的時(shí)候,downloadFile 方法將被調(diào)用。
例子8代碼:FileClient
import java.io.*;
import java.util.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
public class FileClient {
public static void main(String argv[]) {
try {
// create and initialize the ORB
ORB orb = ORB.init(argv, null);
// get the root naming context
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
NamingContext ncRef = NamingContextHelper.narrow(objRef);
NameComponent nc = new NameComponent("FileTransfer", " ");
// Resolve the object reference in naming
NameComponent path[] = {nc};
FileInterfaceOperations fileRef =
FileInterfaceHelper.narrow(ncRef.resolve(path));
if(argv.length < 1) {
System.out.println("Usage: java FileClient filename");
}
// save the file
File file = new File(argv[0]);
byte data[] = fileRef.downloadFile(argv[0]);
BufferedOutputStream output = new
BufferedOutputStream(new FileOutputStream(argv[0]));
output.write(data, 0, data.length);
output.flush();
output.close();
} catch(Exception e) {
System.out.println("FileClient Error: " + e.getMessage());
e.printStackTrace();
}
}
}
運(yùn)行應(yīng)用
最后一步是運(yùn)行這個(gè)應(yīng)用(萬里長征最后一步 哈哈高興吧)。這里有幾個(gè)小的步驟。
1)運(yùn)行CORBA名字服務(wù)。這里可以使用tnameserv命令。它默認(rèn)運(yùn)行在900端口。你還可以改變端口號(hào)
例如使用如下命令讓你的服務(wù)運(yùn)行在2500端口。
prompt> tnameserv -ORBinitialPort 2500
2)運(yùn)行服務(wù)端
如果CORBA名字服務(wù)在默認(rèn)的端口的時(shí)候使用如下命令。
prompt> java FileServer
如果你的CORBA名字服務(wù)在自己定義的端口如2500,使用如下命令,這里使用-ORBInitialPort 來定義端口
prompt> java FileServer -ORBInitialPort 2500
3)創(chuàng)建客戶端的Stubs。我們?cè)谶\(yùn)行客戶端之前我們必須創(chuàng)建一個(gè)Stubs。首先我們要得到一個(gè)FileInterface.idl 的復(fù)制,然后用如下命令編譯。
prompt> idlj -fclient FileInterface.idl
4)運(yùn)行客戶端。現(xiàn)在你可以運(yùn)行客戶端了,以下命令是假定corba名字服務(wù)在2500端口處監(jiān)聽。
prompt> java FileClient hello.txt -ORBInitialPort 2500
這樣hello.txt文件可以從服務(wù)端下載下來了。
另外的,有些選項(xiàng)通過代碼定義的屬性來定義。比如代替初始化orb的代碼如下
ORB orb = ORB.init(argv, null);
它能修改一些參數(shù),使得orb在2500端口提供和corba服務(wù)的名字叫g(shù)osling。例子如下。
Properties props = new Properties();
props.put("org.omg.CORBA.ORBInitialHost", "gosling");
props.put("orb.omg.CORBA.ORBInitialPort", "2500");
ORB orb = ORB.init(args, props);
練習(xí)
在這個(gè)文件交換程序里面,客戶端(不管是corba 還是rmi)需要知道將要下載的文件名,可是沒有方法提供列出可以用到的文件。作為一個(gè)練習(xí),你可能想加入一些方法來比如提供列出可以用到的文件名來提高這個(gè)應(yīng)用程序的可使用性。另外,你可能想開發(fā)一個(gè)基于圖形的客戶端來代替字符客戶端。當(dāng)客戶端運(yùn)行的時(shí)候它調(diào)用一個(gè)在服務(wù)端的方法來得到文件列表然后彈出一個(gè)菜單來顯示所有用戶可以選擇下載的文件。用戶可以選擇一個(gè)或多個(gè)文件來下載. 如下 圖1

Figure 1: GUI-based File Transfer Client
CORBA vs. RMI
從編碼來看,很明顯,RMI對(duì)于java 開發(fā)人員來說很容易使用。他們不需要了解IDL語言 Interface Definition Language 。
然而一般來說corba和RMI在如下方面各不相同。
(1)corba的interfaces(接口)使用IDL來定義,RMI 接口使用java來定義。RMI-IIOP允許所有的interfaces(接口)使用java來編寫。
(2)COrba提供in 和 out參數(shù)。同時(shí)RMI不提供,這是因?yàn)楸镜貙?duì)象能夠復(fù)制。
(3)CORBA使用一種特殊的語言來設(shè)計(jì)interfaces(接口),這意味著一些對(duì)象可以使用java來編寫 而另外一些類可以使用 另外的語言例如C++來編寫它們能夠協(xié)同的工作。因此corba是一種連接各種孤立語言的理想機(jī)制。而RMI只是對(duì)所有java編寫的對(duì)象設(shè)計(jì)的。但是RMI-IIOP提供協(xié)同工作的能力。
(4)CORBA對(duì)象不被自動(dòng)回收.就像我們以上提到的,corba是一種獨(dú)立的特殊語言,另外一些語言(例如C++)不提供垃圾收集。這可能會(huì)造成不利的情況,因?yàn)閏orba對(duì)象一旦創(chuàng)建,它將一直存在直到你殺掉它,而決定一個(gè)對(duì)象什么時(shí)候?qū)⒈粴⒌舨皇且患芎唵蔚墓ぷ鳌6鳵MI對(duì)象能夠自動(dòng)的被收集。
結(jié)論
可以使用RMI和JavaIDL(一個(gè)corba的實(shí)現(xiàn))開發(fā)一個(gè)基于分布式對(duì)象的java應(yīng)用程序。使用這兩種技術(shù)從第一步到定義一個(gè)對(duì)象的接口都是很相似的。
然而和RMI把對(duì)象接口(interfaces)定義在java中不同的是,Corba的對(duì)象接口(interfaces)定義在IDL(Interface Definition Language )中,這樣增加了其他層的復(fù)雜性,使得需要開發(fā)人員需要了解IDL和IDL到j(luò)ava 的映射。
在這兩種機(jī)制之間做選擇依靠手頭的項(xiàng)目和項(xiàng)目的要求。我希望本文能夠給你提供足夠的信息來開始開發(fā)一個(gè)基于對(duì)象分布式應(yīng)用程序和給你提供足夠的指導(dǎo)
來選擇一個(gè)分布機(jī)制。
更多的相關(guān)參考:
- RMI
- CORBA Specification (OMG)
- JavaIDL
- Distributed Programming with Java book (Chapter 11: Overview of CORBA)
- CORBA Server and Servlet Client
- RMI-IIOP
關(guān)于作者
Qusay H. Mahmoud 專門提供關(guān)于 Java 的咨詢和培訓(xùn)。他發(fā)表了許多關(guān)于java的文章 , 它還是
<<Distributed Programming with Java >> (1999)和 <<Learning Wireless Java>>(2000)的作者。