top
Loading...
學習使用RMI
font face="Geneva, Arial, Helvetica" size="3">

學習使用RMI


  1. 編寫Java源代碼和HTML文件的步驟。
  2. class文件和HTML文件的編譯和部署步驟 。
  3. 啟動RMI注冊表、服務程序和小應用程序的 步驟。
本教學課程需要的文件包括:
  • Java遠程接口-- Hello.java
  • 實現examples.hello.Hello接口的Java遠程對象-- HelloImpl.java
  • 調用遠程方法sayHello的Java小應用程序-- HelloApplet.java
  • 引用該小應用程序的主頁的HTML代碼-- hello.html
:本教學課程中的名詞“遠程對象實現”(remote object implementation)、“對象實現”(object implementation)和“ 實現”(implementation)等可互換使用,并均指實現遠程接 口的類examples.hello.HelloImpl。

對于本教學課程中所用的所有源代碼,您可選擇以下 列文件格式下載:

  • RMIgetStart.zip
  • RMIgetStart.tar
  • RMIgetStart.tar.Z

編寫Java源代碼 和HTML文件

因為Java語言要求在一類完全合格的包名稱與至該類的 目錄路徑之間有一個映射,所以,在您開始編寫Java語 句之前,您應該確定包名稱和目錄名稱。此映射可使Java 編譯器知道在哪個目錄查找Java程序所提到的類文件。 對于本教學課程的程序,包名稱是examples.hello,源程序 目錄是$HOME/myscr/examples/hello

要在Solaris上為您的源文件創建目錄,可執行下列指 令:
mkdir -p $HOME/mysrc/examples/hello

在Windows平臺上,您需要進入您選定的目錄,然后鍵 入:
mkdir mysrc
mkdir mysrcexamples
mkdir mysrcexampleshello

在這部分要完成三項工作:

  1. 將遠程類的功能定義為Java接口
  2. 編寫遠程接口實現和服務器類
  3. 編寫一個使用遠程服務的客戶程序
<將遠程類的功能定 義為Java接口

在Java中,遠程對象是實現遠程接口的類的實例。您 的遠程接口將聲明您希望遠程調用的每個方法。遠程接 口具有下列特點:

  • 遠程接口必須被公開聲明。否則,如果一個客戶機程序 與該遠程接口不在同一個包內,那么該客戶機程序在試 圖裝載實現該遠程接口的一個遠程對象時就會得到一個 錯誤。
  • 該遠程接口繼承于java.rmi.Remote接口。
  • 除與應用程序相關的某些異常(Exception)之外,每個方法 都必須在其throws子句中聲明java.rmi.RemoteException (或一個 RemoteException的父類)。
  • 作為一個參數或返回值傳遞(直接或嵌入在本地對象內 )的任何一個遠程對象的數據類型都必須聲明為該遠程 接口類型(例如: Hello),而不能是實現類(HelloImpl)。
遠程接口examples.hello.Hello的接口定義如下。該接口只包 含一個將串返回給調用程序的方法sayHello:
package examples.hello;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Hello extends Remote {
String sayHello() throws RemoteException;
}
因為遠程方法調用失敗的方式可能與本地方法調用非常 不同(因與網絡相關的通信問題和服務程序問題),遠程 方法可能會拋出一個java.rmi.RemoteException以報告通信失敗 。如果您希望詳細了解有關分布式系統的失敗和恢復問 題,請閱讀“ A Note on Distributed Computing”(《分布式計算初步》)一 書。

<編寫遠程接 口實現和服務器類

實現一個遠程對象類至少必須:

  • 聲明它至少實現一個遠程接口
  • 為該遠程對象定義構造方法
  • 為可被遠程調用的方法提供實 現
本文所說的“服務器”類系指具 有一個創建遠程對 象實現的實例、并將該實例與rmiregistry中的一個名稱相 關聯的main方法的類。包含這一main方法的類可能是實現 類本身,也可能是另一個完全不同的類。

在本例中,該main方法是examples.hello.HelloImpl的一部分 。服務器程序必須:

  • 創建并安裝一個安全管理器。
  • 創建某遠程對象的一個或多個實例 。
  • 為了進行引導,在RMI遠程對象 注冊表中至少注冊一個遠程對象。
下面先列出HelloImpl.java的源代碼,然后再詳細解釋上述 6個步驟:
package examples.hello;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;
public class HelloImpl extends UnicastRemoteObject
implements Hello {
public HelloImpl() throws RemoteException {
super();
}

public String sayHello () {
return "Hello World!";
}

public static void main (String args []) {
// Create and install a security manager
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}

try {
HelloImpl obj = new HelloImpl() ;
// Bind this object instance to the name "HelloServer"
Naming.rebind("//myhost/HelloServer", obj);
System.out.println("HelloServer bound in registry");
} catch (Exception e) {
System.out.println("HelloImpl err: " + e.getMessage());
e.printStackTrace();
}
}
}


<實現遠程接口
在Java語言中,當一個類聲明它實現某一接口時,在 該類與編譯器之間達成一個協議。進入該協議后,該類 保證它將為其正在實現的接口所聲明的每種方法提供定 義或主體。接口方法隱含表示為public和abstract,所以, 如果實現類不履行協議,那么根據定義 它就 變成一個abstract類,如果該類沒有被宣布為abstract,那 么,編譯器就會指出這一事實。

本例中的實現類為examples.hello.HelloImpl。實現類聲明它 正在實現的是哪個遠程接口。HelloImpl類聲明如下:

public class HelloImpl extends UnicastRemoteObject implements Hello

作為簡化的類,實現類可擴展一個遠程類,在本例中 為java.rmi.server.UnicastRemoteObject。UnicastRemoteObject擴展后 ,HelloImpl類就能被用來創建一個使用RMI基于缺省的套 接字網絡接口進行傳輸且不間斷運行的遠程對象。

如果您需要一個在客戶程序發出請求時能被創建的遠 程對象,那么在您閱讀完本教學課程后,您可繼續閱讀 Remote Object Activation (《遠程對象的創建》)教學課程。此外 ,您還可在有關創 建定制RMI套接字工廠的教學課程中學習如何使用您 自己的通信協議,而非RMI作為缺省所使用的TCP套接字 網絡接口。

為遠程對象定義構造程序
遠程類的構造程序與非遠程類的構造程序具有相同的 功能:它初始化每個類的新創建實例的變量,并將該類 的一個實例返回給調用該構造程序的程序。

此外,您的遠程對象實例還需要被“輸出”。輸出后 的遠程對象可在一個匿名端口上監聽對遠程方法的調用 請求,并接受進入的遠程方法請求。當您繼承了java.rmi.server.UnicastRemoteObject 或java.rmi.activation.Activatable時,您的類在創建后就會被 自動輸出。

如果您選擇從除UnicastRemoteObject或Activatable以外的任 何類擴展一個遠程對象,則您需要通過從您的類的構造 程序(或另一個初始化方法)中調用UnicastRemoteObject.exportObject 方法或Activatable.exportObject方法公開輸出此遠程對象。

因為對象輸出可能會拋出一個java.rmi.RemoteException例外 ,所以您 必須定義一個拋出RemoteException的構造程 序,即使該構造程序只執行這一項工作。如果您忘記了 該構造程序,則javac將產生下列錯誤信息:

HelloImpl.java:13: Exception java.rmi.RemoteException must be caught, or it must be declared in the throws clause of this method.
Super();
^
1 error
小結:一個遠程對象的實現類必須:
  • 實現一個遠程接口
  • 輸出該對象,以便接受進入的遠程方法調用
  • 聲明其構造程序并至少拋出一個java.rmi.RemoteException
examples.hello.HelloImpl類的構造程序如下:
public HelloImpl() throws RemoteException {
super();
}
請注意:
  • super方法所調用的是輸出遠程對象的java.rmi.server.UnicastRemoteObject 的無參數構造程序。
  • 該構造程序必須拋出java.rmi.RemoteException例外,因為如果 沒有通信資源,則RMI在構造期間輸出一個遠程對象的努 力就會失敗。
盡管對父類的無參數構造程序super()的調用是缺省的(即 使被忽略),但我們還是將其編入上面的例子,目的是 表明這樣的事實:Java VM ( Java虛擬機)在構造一個類之 前構造了其父類。

<為每個遠程方法提供實 現
一個遠程對象的實現類包含實現在遠程接口中所定義 的所有遠程方法的程序代碼。例如,下面就是sayHello方 法的實現,它向調用程序返回字符串"Hello World !":

public String sayHello() throws RemoteException {
return "Hello World !";
}
向遠程方法傳送的參數或來自遠程方法的返回值可以是 包括對象在內的任何Java類型,但條件是這些對象實現 了java.io.Serializable接口。java.lang和java.util中的核心Java 類大多實現了Serializable接口。在RMI中:
  • 缺省情況下,本地對象通過復制傳輸,除了那些標記為 static或transient的元素以外,一個對象的所有數據元素 (或字段)均被復制傳輸。有關如何改變缺省序列化行為 的介紹,請參閱Java Object Serialization Specification ( Java對象序列化技術規范) 。
  • 遠程對象傳輸其引用(reference)。某個遠程對象的一個引 用實際上就是一個存根的引用,而該存根則是該遠程對 象客戶程序方面的代理。RMI 技術規范中對存根有詳細介紹。我們將在本教學課程 中的“使用rmic生成存根及框架”部分創 建它們。
一個類可以定義在遠程接口中沒有規定的方法,但這 些方法只能在提供服務的虛擬機上被調用,而不能被遠 程調用。

創建和安裝安全管理程序
服務器的main方法首先需要創建和安裝一個安全管理 程序:或者是RMISecurityManager,或者是您自己定義的程序 。例如:

if (System.getSecurityManager() == null) {
System.setSecurityManager (new RMISecurityManager());
}
必須運行安全管理程序,因為它能確保所裝載的類不會 執行不允許執行的操作。如果不指定安全管理程序,那 么除了能在本地CLASSPATH中找到的以外,RMI客戶機或服 務器就不允許裝載其它的類。

<創建遠程對象的一個或多個實 例

服務器的main方法需要創建提供服務的遠程對象實現 的一個或多個實例。例如:

HelloImpl obj = new HelloImpl();
構造程序輸出遠程對象,意味著遠程對象一旦被創建就 可以接受進入的調用 叫 。

注冊遠程對象

調用程序(客戶機應用程序、對等體或小應用程序)要 能調用遠程對象的一個方法,則該調用程序必須首先獲 得該遠程對象的一個引用。

對于引導來說,RMI系統提供一個能將類似于"//host/objectname" 的URL格式名稱關聯到遠程對象的遠程對象注冊表,其中 ,objectname是簡單的字符串名稱。

RMI注冊表是一個簡單的可使遠程客戶機獲得向遠程對 象引用的服務器端名稱服務器。它一般只用來找到RMI客 戶機需要與之對話的第一個遠程對象。隨后,這第一個 對象反過來又提供可找到與應用程序相關的其它對象。

例如,引用可以作為一個遠程方法調用的參數或該調 用所獲得的返回值。有關具體的工作原理的討論,請參 閱Applying the Factory Pattern to RMI《將工廠方式應用到RMI》一書 。

遠程對象一旦在服務器上注冊,則調用程序就能按照 名字搜索對象,獲得遠程對象的引用,再遠程調用該對 象的方法。

例如,下列語句將名字"HelloServer"關聯到遠程對象的 引用:

Naming.rebind("//myhost/HelloServer", obj);
請注意以下對有關rebind方法的參數的說明:
  • 第一個參數是URL格式的java.lang.String,表示遠程對象的 地址和名字。
    • 您需要將myhost的值修改為您的服務器名或IP地址。否則 ,如果忽略了URL中的主機名, 將采用當前主機作為 缺省值,而在URL中不必規定協議:如"HelloServer"。
    • 可以在URL中提供端口號作為一個選項:如"//myhost:1234/HelloServer" 。端口號缺省值為1099。只有當服務器在不是缺省端口 1099的端口上創建了注冊表時才需要規定端口號。
  • 第二個參數是將在其上調用遠程方法的對象實現的引用 。
  • 在obj參數所規定的實際遠程對象引用中,RMI運行時替 代向遠程對象的存根的引用。諸如HelloImpl的實例等遠程 實現對象永遠不會離開創建它們的虛擬機,所以,當一 臺客戶機在服務器的遠程對象注冊表中進行搜索時,就 返回一個包含實現存根的對象。
考慮到安全原因,一個應用程序僅可以與在同一主 機上運行的注冊表進行關聯或解除關聯。這樣可以防止 客戶機刪除或重寫服務器遠程注冊表中的任何項目。但 可以從任何主機進行搜索。

<編寫使用遠程服務的 客戶機程序

分布式Hello World例程中的小應用程序遠程調用sayHello 方法,以便得到字符串"Hello World!",而此字符串在該小 應用程序運行時被顯示。該小應用程序的代碼如下:

    package examples.hello;

    import java.applet.Applet;
    import java.awt.Graphics;
    import java.rmi.Naming;
    import java.rmi.RemoteException;

    public class HelloApplet extends Applet {

    String message = "blank";

    // "obj" is the identifier that we"ll use to refer
    // to the remote object that implements the "Hello"
    // interface
    Hello obj = null ;

    public void init() {
    try {
    obj = (Hello)Naming.lookup("//" +
    getCodeBase().getHost() + "/HelloServer");
    message = obj.sayHello();
    } catch (Exception e) {
    System.out.println("HelloApplet exception: " +
    e.getMessage());
    e.printStackTrace();
    }
    }

    public void paint(Graphics g) {
    g.drawString(message, 25, 50);
    }
    }

  1. 首先,該小應用程序從服務器主機的rmiregistry中獲得遠 程對象實現(聲明為"HelloServer")的一個引用。與Naming.rebind 方法相同,Naming.lookup方法也采用URL格式的java.lang.String 。在本例中,小應用程序通過使用getCodeBase方法和getHost 方法構造URL串。Naming.lookup可完成下列任務:
    • 構造注冊表存根實例(以便連接服務器的注冊表),使用 主機名和端口號作為向Naming.lookup提供的參數
    • 使用注冊表存根調用注冊表上的遠程lookup方法,使用URL 的名稱部分("HelloServer")
      • 注冊表返回與該名稱相關聯的helloImpl_Stub實例
      • 接收遠程對象實現(HelloImpl)存根實例并從CLASSPATH或存根 的代碼庫(codebase)中裝載存根類(examples.hello.HelloImpl_Stub)
    • Naming.lookup將存根返回給調用程序(HelloApplet)
  2. 小應用程序調用服務器遠程對象的遠程sayHello方法
    • RMI序列化應答字符串"Hello World!"并返回
    • RMI使字符串解除順列化,并將其存儲在名為message的變 量中
  3. 小應用程序調用paint方法,使字符串"Hello World!"在小應 用程序的繪圖區顯示出來。
構造后要作為參數傳遞給Naming.lookup方法的URL字符 串必須包含服務器的主機名。否則,小應用程序就會按 照缺省方式向客戶機搜索,而AppletSecurityManager就會拋出 一個例外,因為小應用程序不能存取本地系統,而只能 與小應用程序的主機進行通信。

引用Hello World小應用程序的主頁的HTML語句如下:

$#@60;HTML>
$#@60;title>Hello World$#@60;/title>
$#@60;center> $#@60;h1>Hello World$#@60;/h1> $#@60;/center>

The message from the HelloServer is:
$#@60;p>
$#@60;applet codebase="myclasses/"
code="examples.hello.HelloApplet"
width=500 height=120>
$#@60;/applet>
$#@60;/HTML>

請注意:
  • 您希望從中下載Java類(classes)的計算機上必須有HTTP服 務程序運行。
  • 本例中的codebase在主頁本身被下載的目錄下指定一個子 目錄。使用這種相對路徑通常是比較好的方法。例如, 如果被小應用程序的HTML所引用的codebase目錄(其中包含 小應用程序的類文件)是在HTML目錄以上的目錄,則您可 能就需要使用諸如“http://www.zhujiangroad.com/”的相對路徑。
  • 小應用程序的code屬性規定了小應用程序的完全合格的 包名字,在本例中為examples.hello.HelloApplet:

    • code="examples.hello.HelloApplet" <

類文件和HTML文 件的編譯和部署

Hello World例子中的源代碼現在已經完成,$HOME/mysrc/examples/hello 目錄中有以下4個文件:
  • 包含Hello遠程接口源代碼的Hello.java。
  • 作為HelloImpl遠程對象實現源代碼及Hello World小應用程序 服務器的HelloImpl.java。
  • 小應用程序的源代碼HelloAplet.java。
  • 作為引用Hello World小應用程序的主頁hello.html。
在本節中,您將對.java源文件進行編譯并創建.class文件 。隨后,您將運行rmic編譯程序以創建存根和框架。存 根是客戶機端將RMI調用傳送給服務器端調度程序的遠程 對象代理,而服務器端的調度程序又反過來將調用傳送 給實際的遠程對象實現。

在使用javac和rmic編譯器時,您必須規定所產生的類 文件應該存儲在什么地方。對于小應用程序,所有文件 均應駐留在小應用程序的代碼庫(codebase)目錄中。在本 例中,這個目錄就是$HOME/public_html/muclasses。

某些Web服務器允許通過構造“http://host/'username/” 這樣的HTTP URL存取用戶的public_html目錄。如果您的Web服 務器不支持這種方式,則您可使用格式為"file://home/username/public_html" 的URL文件。

本節完成以下4項任務:

  1. Java源文件的編譯
  2. 使用rmic創建存根和框架
  3. 將HTML文件移動到部署目錄
  4. 為運行設置路徑
<Java源文件的編譯
在進行編譯之前,必須確保部署目錄$HOME/public_html/myclassess 和開發目錄$HOME/mysrc/examples/hello能夠通過計算機的CLASSPATH 進行存取。

要對Java源文件進行編譯,則應運行下列javac指令:
javac -d $HOME/public_html/myclassess Hello.java HelloImpl.java HelloApplet.java
此指令在目錄$HOME/public_html/myclasses內創建目錄examples/hello (如果它不存在的話)。隨后,然后將文件Hello.class、HelloImpl.class 和helloApplet.class寫入該目錄。這三個文件分別是遠程接 口、實現和小應用程序。有關javac選項的說明,可參閱 Solaris 的javac指南或Win32 javac指南。

使用rmic創建框架和存根
要創建存根和框架文件,可對包含my.package.MyImpl等遠 程對象實現的編譯好的類文件(.class)的完全合格的包名 字運行編譯程序rmic。rmic指令以一個或多個類名字作為 參數,并以MyImpl_Skel.class和MyImpl_Stub.class的格式產生類 文件。

按照缺省設置,在JDK1.2中,rmic在運行時,-vcompat標 志保持打開(on),利用該標志可生成支持存取下列對象的 存根和框架:

  1. 來自1.1客戶端的Unicast (非Activatable )遠程對象
  2. 來自1.2客戶端的所有類型的遠程對象
如果您只需要支持1.2的客戶端,則rmic可以-v1.2選項運 行。有關rmic選項的詳細介紹,請參閱Solaris rmic指南或Win32 rmic指南。

例如,要為HelloImpl遠程對象實現創建存根和框架,可 按照如下方式運行rmic:
rmic -d $HOME/public_html/myclasses examples.hello.HelloImpl
-d選項表示存放編譯后的存根和框架類文件的根目錄 。所以,上述指令可在目錄$HOME/public_html/myclasses/examples/hello 中創建下列文件:

HelloImpl_Stub.class
HelloImpl_Skel.class
所創建的存根類實現了與遠程對象完全相同的遠程接口 集。即,客戶機可使用Java語言內置的運算符進行運算 和類型檢查。這還表明,Java遠程對象支持真正面向對 象的多機組合形式。

<將HTML文件移動到部署目錄
要使客戶端能看到引用小應用程序的主頁,就必須把 hello.html文件從開發目錄移動到小應用程序的codebase目 錄中。例如:
mv $HOME/mysrc/examples/hello/hello.html $HOME/public_html/

為運行設置路徑
在運行HelloImpl服務程序時,必須確保能夠通過服務 器的CLASSPATH存取$HOME/public_html/codebase目錄。

啟動RMI注冊表、 服務程序和小應用程序

本節將完成以下三項任務:
  1. 啟動RMI注冊表
  2. 啟動服務程序
  3. 運行小應用程序


啟動RMI注冊表
RMI注冊表是允許遠程客戶機獲得向一個遠程對象的 引用的、簡單的、服務端的名稱服務器。它一般只用來 尋找應用程序需要與之對話的第一個遠程對象。隨后, 該對象又可提供與應用程序相關的支持以尋找其他對象 。

注意: 在啟動rmiregistry之 前,您必須確定您將在其上運行registry的平臺或窗口沒 有設置CLASSPATH,或者在CLASSPATH 中不包含指向您希望 向您的客戶機下載任何類的路徑,這其中包括您的遠程 對象實現類的存根。

如果在您啟動rmiregistry之后,它能在其CLASSPATH中找 到您的存根類,則它將忽略服務器的java.rmi.server.codebase 屬性,因此,您的客戶機就不能為您的遠程對象下載存 根代碼。

要在服務器上啟動registry,可執行rmiregistry指令。此 指令不產生輸出,而且一般只在后臺運行。有關rmiregistry 的詳細介紹,請參閱Solaris rmiregistry指南或Win32 rmiregistry指南。

例如,在Solaris平臺上:
rmiregistry &

又如,在Windows 95或Windows NT平臺上:
start rmiregistry
(如果不存在start指令,可使用javaw )。

注冊表運行的缺省端口是1099。要在另一個端口上啟 動注冊表,可從指令行指定端口號。例如,要在Windows NT系統的端口2001上啟動注冊表:
start rmiregistry 2001

如果注冊表在非缺省的端口上運行,您就需要在對注 冊表進行調用時傳遞給java.rmi.Naming類的基于URL的名字 中指定端口號。例如,在Hello World例子中如果注冊表在 端口2001上運行,則將HelloServer的URL與遠程對象引用產 生關聯的調用就會是:
Naming.rebind("//myhost:2001/HelloServer", obj);

每次對遠程接口進行修改后,或在遠程對象實現中 使用了修改/添加的遠程接口后,都必須先停止注冊表 ,然后再重新啟動。否則,在注冊表中關聯的對象引用 類型就會與修改后的類不相符。

<啟動服務程序
在啟動服務程序時,必須指定java.rmi.server.codebase屬 性,這樣才能動態地將存根類下載到注冊表及客戶機。 運行服務程序,將codebase屬性設置為實現存根的地點。 因為codebase屬性只能引用一個目錄,所以必須確定在被 java.rmi.server.codebase所引用的目錄中已經安裝了需要下載 的所有類。

欲知有關每個java.rmi.server屬性的說明,請 點按這里。要察看所有java.rmi.activation屬性,請 點按這里。有關java選項的詳細介紹,請參閱Solaris java指南或Win32 java指南。如果在運行本例程序時發生問題,請參閱 RMI and Serialization FAQ ( RMI及系列化問答)。

注: 只有當本地計算機不存在存根類, 已經在類文件所駐留的服務器上正確設置了java.rmi.server.codebase 屬性時,才將存根類動態地下載到客戶機的虛擬機上。

同一個指令行需要包含4項內容:"java"指令、兩個屬 性name = value對(對于codebase屬性,注意從“-D”直 到“/”都沒有空格),服務器程序完全合格的包名字。 在單詞"java"之后應該有一個空格,在兩個屬性之間也應 該有空格,在單詞"examples" (在瀏覽器或紙面上如果以文 本方式查閱,這個單詞很難看清楚)之前也有空格。下 列指令表示如何啟動HelloImpl服務程序,指定java.rmi.server.codebase 和java.security.policy屬性:

java -Djava.rmi.server.codebase = http://myhost/'myusername/myclasses/ -Djava.security.policy=$HOME/mysrc/policy examples.hello.HelloImpl

為了在您的系統上運行這個程序,您需要將policy文件 的地址修改為您系統中已經安裝了本例源代碼的目錄。 注:在本例中,為簡單起見,我們將使用允許任何 地方的任何人訪問的策 略文件。不要在運行環境中使用這一策略文件。 有關如何使用java.security.policy文件正確打開許可的詳細 介紹,請參閱以下文件:

http://java.sun.com/products/jdk/1.2/docs/guide/
security/PolicyFiles.html

http://java.sun.com/products/jdk/1.2/docs/guide/
security/permission.html

codebase屬性將設置為URL,所以,其格式應該是"http://aHost/somesource/" 或"file:/myDirectory/location/",或者根據某些操作系統的要 求,"file:///myDirectory/location/" ("file"單詞后應該有三個斜 杠)。

請注意,本例中URL字符串的結尾都有“/”符號。這 個結尾斜杠是java.rmi.server.codebase屬性對URL地址的要求 ,這樣,實現才能正確地找到您的類定義。

如果您忘記了在codebase屬性后面寫上結尾斜杠,或者 如果在資源中找不到類文件(這些文件尚未準備好下載 ),或者如果您拼寫錯了屬性名稱,您將得到java.lang.ClassNotFoundException 例外。當您試圖將遠程對象關聯到rmiregistry時,或者當 第一臺客戶機試圖存取對象的存根時,就會拋出這樣的 例外。如果后一種情形發生,您就會遇到另一個問題, 因為rmiregistry正在其CLASSPATH中尋找存 根。

輸出結果應該如下:
HelloServer bound in registry

<

作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗