第 7 章
主題:
概述
激活協(xié)議
“可激活”遠(yuǎn)程對(duì)象的實(shí)現(xiàn)模型
激活接口
.1 概述
分布式對(duì)象系統(tǒng)被設(shè)計(jì)為支持長(zhǎng)期存在的持久對(duì)象。假設(shè)這些系統(tǒng)將由成千(也
許成萬(wàn))個(gè)這樣的對(duì)象組成,則對(duì)象的實(shí)現(xiàn)在無(wú)限期的時(shí)間段內(nèi)被激活并保持活
動(dòng)狀態(tài)是不合理的。這將占用寶貴的系統(tǒng)資源。另外,客戶(hù)機(jī)需要保存對(duì)對(duì)象的
持久引用的能力,這樣在一個(gè)系統(tǒng)崩潰后可以重新建立對(duì)象之間的通訊,因?yàn)橥?nbsp;
常對(duì)一個(gè)分布對(duì)象的引用只有當(dāng)對(duì)象處于活動(dòng)狀態(tài)時(shí)才有效。
對(duì)象激活是一種用來(lái)提供對(duì)對(duì)象持久引用和管理對(duì)象實(shí)現(xiàn)的執(zhí)行的機(jī)制。在 RMI
中,激活允許對(duì)象根據(jù)需要開(kāi)始執(zhí)行。當(dāng)訪問(wèn)(通過(guò)方法調(diào)用)“可激活”遠(yuǎn)程
對(duì)象時(shí),如果該遠(yuǎn)程對(duì)象當(dāng)前尚未執(zhí)行,則系統(tǒng)將在適當(dāng)?shù)?nbsp;Java 虛擬機(jī)中開(kāi)始
該對(duì)象的執(zhí)行。
7.1.1 術(shù)語(yǔ)
活動(dòng) (active) 對(duì)象是在某些系統(tǒng)的 Java 虛擬機(jī)中被實(shí)例化并被導(dǎo)出的遠(yuǎn)程對(duì)
象。非活動(dòng)對(duì)象在虛擬機(jī)中尚未被實(shí)例化(或?qū)С觯?,但能變成活?dòng)狀態(tài)的遠(yuǎn)程
對(duì)象。激活就是將非活動(dòng)對(duì)象轉(zhuǎn)化為活動(dòng)對(duì)象的過(guò)程。激活要求對(duì)象與一臺(tái)虛擬
機(jī)相關(guān)聯(lián),而這將可能需要將該對(duì)象的類(lèi)加載到虛擬機(jī)中,同時(shí)該對(duì)象也恢復(fù)其
持久狀態(tài)(如果有)。
在 RMI 系統(tǒng)中,我們使用了惰性激活。惰性激活就是將一個(gè)對(duì)象的激活延遲到客
戶(hù)機(jī)第一次使用該對(duì)象時(shí)(即第一次方法調(diào)用時(shí))。
7.1.2 惰性激活
遠(yuǎn)程對(duì)象的惰性激活是用不完善遠(yuǎn)程引用(有時(shí)稱(chēng)為不完善塊)實(shí)現(xiàn)的。對(duì)遠(yuǎn)程
對(duì)象的不完善遠(yuǎn)程引用在第一次調(diào)用對(duì)象的方法時(shí),“完善”為活動(dòng)對(duì)象的引用
。每個(gè)不完善引用均保持一個(gè)持久句柄(激活標(biāo)識(shí)符)和對(duì)目標(biāo)遠(yuǎn)程對(duì)象的瞬態(tài)
遠(yuǎn)程引用。遠(yuǎn)程對(duì)象的激活標(biāo)識(shí)符包含足夠的信息來(lái)使第三方激活該對(duì)象。瞬態(tài)
引用是對(duì)可用來(lái)聯(lián)系執(zhí)行對(duì)象的主動(dòng)遠(yuǎn)程對(duì)象的“活動(dòng)”引用。
在不完善引用中,如果對(duì)遠(yuǎn)程對(duì)象的活引用為空,則不認(rèn)為目標(biāo)對(duì)象是主動(dòng)的。
在方法調(diào)用中,不完善引用(對(duì)該對(duì)象)將加入激活協(xié)議以獲得“活”引用,該
引用是對(duì)新激活的對(duì)象的遠(yuǎn)程引用(例如單路傳送 (unicast) 的遠(yuǎn)程引用)。一
旦不完善引用得到活引用,則不完善引用將把方法調(diào)用傳給底層的遠(yuǎn)程引用,而
該遠(yuǎn)程引用又將方法調(diào)用傳給遠(yuǎn)程對(duì)象。
具體的說(shuō),遠(yuǎn)程對(duì)象的 stub 包含一個(gè)“不完善”遠(yuǎn)程引用類(lèi)型,該類(lèi)型既包括:
遠(yuǎn)程對(duì)象的激活標(biāo)識(shí)符,又包括
“活”引用(可能為空),其中包含遠(yuǎn)程對(duì)象的“活動(dòng)”遠(yuǎn)程引用類(lèi)型(例如,
帶有單路傳送語(yǔ)義的遠(yuǎn)程引用類(lèi)型)。
----------------------------------------------------------------------
----------
注意 - RMI 系統(tǒng)對(duì)遠(yuǎn)程調(diào)用保留“至多一次”語(yǔ)義。換句話說(shuō),對(duì)可激活或單路
傳送遠(yuǎn)程對(duì)象的調(diào)用將至多發(fā)送一次。因此,如果對(duì)遠(yuǎn)程對(duì)象的調(diào)用失?。ㄓ蓲?nbsp;
出的 RemoteException 異常表示),則客戶(hù)機(jī)將得到如下保證:遠(yuǎn)程方法的執(zhí)行
不會(huì)超過(guò)一次,甚至根本就不執(zhí)行。
7.2 激活協(xié)議
在遠(yuǎn)程方法調(diào)用期間,如果目標(biāo)對(duì)象的“活”(live) 引用是未知的,則不完善引
用將褂眉せ钚欏<せ钚榘ㄏ鋁屑父鍪堤澹翰煌晟埔謾⒓せ釔鰲ava 虛
擬機(jī)中的激活組和被激活的遠(yuǎn)程對(duì)象。
激活器(通常每個(gè)主機(jī)有一個(gè))是一個(gè)實(shí)體,負(fù)責(zé)激活,它是:
將激活標(biāo)識(shí)符映射到激活對(duì)象所需信息(對(duì)象的類(lèi)、位置 -- URL 路徑 -- 從該
處可加載類(lèi)、對(duì)象可能需要用于自舉 (bootstrap) 的特定數(shù)據(jù)等)的信息數(shù)據(jù)庫(kù),及
Java 虛擬機(jī)的管理器,它啟動(dòng)虛擬機(jī)(必要時(shí))并將對(duì)象激活請(qǐng)求(和必要的信
息一起)傳送到遠(yuǎn)程虛擬機(jī)中正確的激活組。
注意:激活器始終將激活標(biāo)識(shí)符到活動(dòng)對(duì)象的當(dāng)前映射保存在緩存中,這樣就無(wú)
需為每個(gè)激活請(qǐng)求而查詢(xún)?cè)摻M。
激活組(每個(gè) Java 虛擬機(jī)中一個(gè))是這樣的實(shí)體,它接收對(duì)激活 Java 虛擬機(jī)
中對(duì)象的請(qǐng)求并將激活的對(duì)象返給激活器。
激活協(xié)議如下所示。不完善引用使用一個(gè)激活標(biāo)識(shí)符并調(diào)用激活器(內(nèi)部 RMI 接
口)來(lái)激活與該標(biāo)識(shí)符關(guān)聯(lián)的對(duì)象。激活器查找對(duì)象的激活描述符(先前已注冊(cè)
)。對(duì)象的描述符包括:
對(duì)象的組標(biāo)識(shí)符(指定對(duì)象激活時(shí)所處的虛擬機(jī)),
對(duì)象的類(lèi)名,
URL 路徑,從該處加載對(duì)象的類(lèi)代碼,
特定于對(duì)象的已編組的初始化數(shù)據(jù)(例如,初始化數(shù)據(jù)可能是包含對(duì)象持久狀態(tài)
的文件的名稱(chēng))。
如果應(yīng)容納該對(duì)象的激活組存在,則激活器將激活請(qǐng)求傳送到該組。如果激活組
不存在,則激活器將啟動(dòng)虛擬機(jī)以執(zhí)行激活組,然后將激活請(qǐng)求傳送到該組。
激活組將加載對(duì)象的類(lèi)并用特定的構(gòu)造函數(shù)來(lái)實(shí)例化該對(duì)象。此構(gòu)造函數(shù)帶多個(gè)
參數(shù),包括先前注冊(cè)的激活描述符。
對(duì)象完成激活時(shí),激活組將把已編組對(duì)象引用傳回激活器,然后該激活器記錄激
活標(biāo)識(shí)符和激活引用對(duì),并將活動(dòng)(活)引用返給不完善引用。隨后,不完善引
用(在 stub 內(nèi))通過(guò)活動(dòng)引用將方法調(diào)用直接傳給遠(yuǎn)程對(duì)象。
----------------------------------------------------------------------
----------
注意 - 在 JDK 中,RMI 提供激活系統(tǒng)接口的實(shí)現(xiàn)。要使用激活,必須首先運(yùn)行
激活系統(tǒng)守護(hù)進(jìn)程 (daemon) rmid。
7.3 “可激活”遠(yuǎn)程對(duì)象的實(shí)現(xiàn)模型
為了使可通過(guò)激活標(biāo)識(shí)符訪問(wèn)的遠(yuǎn)程對(duì)象不受時(shí)間影響,開(kāi)發(fā)人員必須做到:
為該遠(yuǎn)程對(duì)象注冊(cè)一個(gè)激活描述符
在對(duì)象的類(lèi)中包含一個(gè)專(zhuān)用構(gòu)造函數(shù),當(dāng) RMI 系統(tǒng)激活可激活對(duì)象時(shí)將調(diào)用它。
可用以下幾種方法來(lái)注冊(cè)激活描述符 (ActivationDesc):
調(diào)用類(lèi) Activatable 的靜態(tài) register 方法
用 Activatable 類(lèi)的第一個(gè)或第二個(gè)構(gòu)造函數(shù)創(chuàng)建“可激活”對(duì)象
顯式地導(dǎo)出“可激活”對(duì)象。該過(guò)程可用 Activatable 的第一個(gè)或第二個(gè) expo
rtObject 方法實(shí)現(xiàn),其參數(shù)為 ActivationDesc、Remote 對(duì)象的實(shí)現(xiàn)和端口號(hào)。
對(duì)于特定對(duì)象,只可用上述三種方法之一來(lái)注冊(cè)激活對(duì)象。有關(guān)如何實(shí)現(xiàn)可激活
對(duì)象的示例,請(qǐng)參閱后面的“構(gòu)造可激活遠(yuǎn)程對(duì)象”。
7.3.1 ActivationDesc 類(lèi)
ActivationDesc 含有激活對(duì)象所需的信息。它包含對(duì)象的激活組標(biāo)識(shí)符、對(duì)象的
類(lèi)名、加載對(duì)象代碼的 codebase 路徑(或 URL)及 MarshalledObject(可包含
每次激活期間所用的對(duì)象特定初始化數(shù)據(jù))。
激活過(guò)程中將查詢(xún)?cè)诩せ钕到y(tǒng)中注冊(cè)的描述符以獲取有關(guān)的信息,從而用于重新
創(chuàng)建或激活對(duì)象。對(duì)象的描述符中的 MarshalledObject 將作為第二個(gè)參數(shù)傳給
遠(yuǎn)程對(duì)象的構(gòu)造函數(shù),以供激活過(guò)程使用。
package java.rmi.activation;
public final class ActivationDesc implements java.io.Serializable
{
public ActivationDesc(String className, String codebase,
java.rmi.MarshalledObject data)
throws ActivationException;
public ActivationDesc(String className, String codebase,
java.rmi.MarshalledObject data,
boolean restart)
throws ActivationException;
public ActivationDesc(ActivationGroupID groupID,
String className,
String codebase,
java.rmi.MarshalledObject data,
boolean restart);
public ActivationDesc(ActivationGroupID groupID,
String className,
String codebase,
java.rmi.MarshalledObject data);
public ActivationGroupID getGroupID();
public String getClassName();
public String getLocation();
public java.rmi.MarshalledObject getData()
public boolean getRestartMode();
}
ActivationDesc 的第一個(gè)構(gòu)造函數(shù)構(gòu)造一個(gè)對(duì)象的對(duì)象描述符,這個(gè)對(duì)象的類(lèi)是
className(可從 codebase 路徑加載),它的初始化信息(已編組形式)為 d
ata。如果使用這種形式的構(gòu)造函數(shù),則對(duì)象的組標(biāo)識(shí)符缺省為該虛擬機(jī) Activa
tionGroup 的當(dāng)前標(biāo)識(shí)符。具有相同 ActivationGroupID 的所有對(duì)象都將在同一
虛擬機(jī)中被激活。如果當(dāng)前組是非活動(dòng)的或無(wú)法創(chuàng)建缺省組,則將拋出 Activat
ionException。如果 groupID 為 null,則將拋出 IllegalArgumentException。
----------------------------------------------------------------------
----------
注意 - 作為創(chuàng)建 ActivationDesc 的副效應(yīng),如果該虛擬機(jī)的 ActivationGrou
p 當(dāng)前不是活動(dòng)的,則將創(chuàng)建缺省 ActivationGroup。缺省激活組將 java.rmi.
RMISecurityManager 作為安全管理器,并在重新激活時(shí)將激活組虛擬機(jī)中的屬性
設(shè)置為該虛擬機(jī)中的當(dāng)前屬性。如果應(yīng)用程序需用不同的安全管理器,則在創(chuàng)建
缺省 ActivationDesc 之前必須設(shè)置該虛擬機(jī)的組。有關(guān)如何為虛擬機(jī)創(chuàng)建 Act
ivationGroup 的詳細(xì)信息,參見(jiàn)方法 ActivationGroup.createGroup。
----------------------------------------------------------------------
----------
ActivationDesc 第二個(gè)構(gòu)造函數(shù)構(gòu)造對(duì)象描述符的方式與第一個(gè)構(gòu)造函數(shù)相同,
但必須提供附加的參數(shù) restart。如果對(duì)象要求重啟服務(wù),這意味著當(dāng)激活器重
新啟動(dòng)時(shí),對(duì)象也會(huì)自動(dòng)重新啟動(dòng)(與根據(jù)需要激活的惰性激活相反)。此時(shí),
restart 應(yīng)為 true。如果 restart 為 false,則對(duì)象將只是在需要時(shí)激活(通
過(guò)遠(yuǎn)程方法調(diào)用)。
ActivationDesc 的第三個(gè)構(gòu)造函數(shù)構(gòu)造一個(gè)對(duì)象的對(duì)象描述符。這個(gè)對(duì)象的組標(biāo)
識(shí)符為 groupID,它的類(lèi)名為 className(可從 codebase 路徑加載),它的初
始化信息為 data。所有具有相同 groupID 的對(duì)象都將在同一 Java 虛擬機(jī)中被
激活。
ActivationDesc 第四個(gè)構(gòu)造函數(shù)構(gòu)造對(duì)象描述符的方式與第三個(gè)構(gòu)造函數(shù)相同,
但它允許指定重啟模式。如果對(duì)象需要重新啟動(dòng)(定義如上),則 restart 應(yīng)為
true。
getGroupID 方法返回該描述符所指定對(duì)象的組標(biāo)識(shí)符。組可以提供一種將對(duì)象聚
合到單一 Java 虛擬機(jī)中的方法。
getClassName 方法返回該激活描述符所指定對(duì)象的類(lèi)名。
getLocation 方法返回用于下載該對(duì)象的類(lèi)的 codebase 路徑。
getData 方法返回一個(gè)“已編組對(duì)象”,該編組對(duì)象包含用于初始化(激活)描
述符指定的對(duì)象的數(shù)據(jù)。
getRestartMode 方法在該對(duì)象的重啟模式啟用時(shí)返回 true,否則返回 false。
7.3.2 ActivationID 類(lèi)
激活協(xié)議利用激活標(biāo)識(shí)符來(lái)表示不受時(shí)間影響的可激活遠(yuǎn)程對(duì)象。激活標(biāo)識(shí)符(
類(lèi) ActivationID 的實(shí)例)含有激活對(duì)象所需的若干信息:
對(duì)象激活器的遠(yuǎn)程引用
對(duì)象的唯一標(biāo)識(shí)符。
對(duì)象的激活標(biāo)識(shí)符可通過(guò)向激活系統(tǒng)注冊(cè)對(duì)象來(lái)得到??捎孟率鰩追N方法之一來(lái)
完成注冊(cè)(如上所述):
通過(guò) Activatable.register 方法
通過(guò)第一個(gè)或第二個(gè) Activatable 構(gòu)造函數(shù)(都有三個(gè)參數(shù)而且注冊(cè)并導(dǎo)出對(duì)象
)
通過(guò)第一個(gè)或第二個(gè) Activatable.exportObject 方法(它們以激活描述符、對(duì)
象實(shí)現(xiàn)及端口為參數(shù),且都注冊(cè)并導(dǎo)出對(duì)象)。
package java.rmi.activation;
public class ActivationID implements java.io.Serializable
{
public ActivationID(Activator activator);
public Remote activate(boolean force)
throws ActivationException, UnknownObjectException, java.rmi.RemoteException;
public boolean equals(Object obj);
public int hashCode();
}
ActivationID 的構(gòu)造函數(shù)接受參數(shù) activator,該參數(shù)指定對(duì)激活器(負(fù)責(zé)激活
與該激活標(biāo)識(shí)符關(guān)聯(lián)的對(duì)象)的遠(yuǎn)程引用。ActivationID 的實(shí)例是全局唯一的。
activate 方法將激活與該激活標(biāo)識(shí)符關(guān)聯(lián)的對(duì)象。如果 force 參數(shù)為 true,激
活器將把遠(yuǎn)程對(duì)象的任何高速緩存引用視為已過(guò)時(shí),從而迫使激活器在激活對(duì)象
時(shí)與組聯(lián)系。如果 force 為 false,則返回可接受的高速緩存值。如果激活失敗
,則拋出 ActivationException。如果激活器不能識(shí)別該對(duì)象標(biāo)識(shí)符,則該方法
將拋出 UnknownObjectException。如果對(duì)激活器的遠(yuǎn)程調(diào)用失敗,則拋出
RemoteException。
equals 方法可實(shí)現(xiàn)基于內(nèi)容的相等比較。如果所有的域都相等(完全相同或從各
域的 Object.equals 語(yǔ)義上等價(jià)),它將返回 true。如果 p1 和 p2 是類(lèi) Act
ivationID 的實(shí)例,則在 p1.equals(p2) 返回 true 時(shí) hashCode 方法返回相同
的值。
7.3.3 Activatable 類(lèi)
Activatable 類(lèi)提供對(duì)需要持久訪問(wèn)而不受時(shí)間影響,同時(shí)又被系統(tǒng)激活的遠(yuǎn)程
對(duì)象的支持。類(lèi) Activatable 是開(kāi)發(fā)人員用來(lái)實(shí)現(xiàn)和管理可激活對(duì)象的主要應(yīng)用
程序接口。注意,必須先運(yùn)行激活系統(tǒng)守護(hù)進(jìn)程 rmid,然后才能注冊(cè)和/或激活
對(duì)象。
package java.rmi.activation;
public abstract class Activatable
extends java.rmi.server.RemoteServer
{
protected Activatable(String codebase,
java.rmi.MarshalledObject data,
boolean restart,
int port)
throws ActivationException, java.rmi.RemoteException;
protected Activatable(String codebase,
java.rmi.MarshalledObject data,
boolean restart,
int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
throws ActivationException, java.rmi.RemoteException;
protected Activatable(ActivationID id, int port)
throws java.rmi.RemoteException;
protected Activatable(ActivationID id, int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
throws java.rmi.RemoteException;
protected ActivationID getID();
public static Remote register(ActivationDesc desc)
throws UnknownGroupException, ActivationException,
java.rmi.RemoteException;
public static boolean inactive(ActivationID id)
throws UnknownObjectException, ActivationException,
java.rmi.RemoteException;
public static void unregister(ActivationID id)
throws UnknownObjectException, ActivationException,
java.rmi.RemoteException;
public static ActivationID exportObject(Remote obj,
String codebase,
MarshalledObject data,
boolean restart,
int port)
throws ActivationException, java.rmi.RemoteException;
public static ActivationID exportObject(Remote obj,
String codebase,
MarshalledObject data,
boolean restart,
int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
throws ActivationException, java.rmi.RemoteException;
public static Remote exportObject(Remote obj,
ActivationID id,
int port)
throws java.rmi.RemoteException;
public static Remote exportObject(Remote obj,
ActivationID id,
int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
throws java.rmi.RemoteException;
public static boolean unexportObject(Remote obj, boolean force)
throws java.rmi.NoSuchObjectException;
}
可激活遠(yuǎn)程對(duì)象的實(shí)現(xiàn)可能擴(kuò)展或不擴(kuò)展類(lèi) Activatable。確實(shí)擴(kuò)展 Activatab
le 類(lèi)的遠(yuǎn)程對(duì)象實(shí)現(xiàn)將從超類(lèi) java.rmi.server.RemoteObject 中繼承 hashCo
de 和 equals 方法中的相應(yīng)定義。因此,引用同一 Activatable 遠(yuǎn)程對(duì)象的兩
個(gè)遠(yuǎn)程引用是相等的(equals 方法將返回 true)。同樣,類(lèi) Activatable 的實(shí)
例將“等于”該實(shí)例的相應(yīng) stub 對(duì)象(即如果 Object.equals 方法用與該實(shí)現(xiàn)
匹配的 stub 對(duì)象作為參數(shù)進(jìn)行調(diào)用,它將返回 true。反之亦然)。
Activatable 類(lèi)方法
Activatable 類(lèi)的第一個(gè)構(gòu)造函數(shù)用于在指定 port 上注冊(cè)和導(dǎo)出對(duì)象(如果 p
ort 為零,則選用某個(gè)匿名端口)。下載的類(lèi)代碼對(duì)象的 URL 路徑是 codbase,
其初始化數(shù)據(jù)是 data。如果 restart 為 true,則對(duì)象將在激活器重新啟動(dòng)或組
失效時(shí)自動(dòng)重新啟動(dòng)。如果 restart 為 false,則對(duì)象將根據(jù)需要而激活(通過(guò)
對(duì)對(duì)象的遠(yuǎn)程方法調(diào)用)。
Activatable 類(lèi)的具體子類(lèi)必須調(diào)用該構(gòu)造函數(shù)才能在初始構(gòu)造期間注冊(cè)和導(dǎo)出
該對(duì)象。作為構(gòu)造可激活對(duì)象時(shí)的副效應(yīng),遠(yuǎn)程對(duì)象將被“注冊(cè)”到激活系統(tǒng)上
并“導(dǎo)出”(如果 port 為零,則在匿名端口導(dǎo)出)到 RMI 運(yùn)行時(shí),從而使之可
接受來(lái)自客戶(hù)機(jī)的到來(lái)調(diào)用。
如果向激活系統(tǒng)注冊(cè)對(duì)象失敗,則該構(gòu)造函數(shù)將拋出 ActivationException。如
果將對(duì)象導(dǎo)出到 RMI 運(yùn)行時(shí)失敗,則將拋出 RemoteException。
第二個(gè)構(gòu)造函數(shù)與第一個(gè) Activatable 構(gòu)造函數(shù)相同,但它允許將客戶(hù)機(jī)和服務(wù)
器套接字工廠規(guī)范用于與該可激活對(duì)象進(jìn)行通訊。詳細(xì)信息,參見(jiàn)“RMI 套接字
工廠”。
第三個(gè)構(gòu)造函數(shù)用于激活對(duì)象并從指定的 port 將其(用 ActivationID,id)導(dǎo)
出。當(dāng)對(duì)象本身被其專(zhuān)用的“激活”構(gòu)造函數(shù)激活時(shí),Activatable 類(lèi)的具體子
類(lèi)必須調(diào)用該構(gòu)造函數(shù)。該“激活”構(gòu)造函數(shù)的參數(shù)必須是:
對(duì)象的激活標(biāo)識(shí)符 (ActivationID) 及
對(duì)象的初始化/自舉數(shù)據(jù) (MarshalledObject)。
作為構(gòu)造的副效應(yīng),遠(yuǎn)程對(duì)象將被“導(dǎo)出”到 RMI 運(yùn)行時(shí)中(從指定 port)并
可接受來(lái)自客戶(hù)機(jī)的調(diào)用。如果將對(duì)象導(dǎo)出到 RMI 運(yùn)行時(shí)失敗,則該構(gòu)造函數(shù)將
拋出 RemoteException。
第四個(gè)構(gòu)造函數(shù)與第三個(gè)構(gòu)造函數(shù)相同,但它允許將客戶(hù)機(jī)和服務(wù)器套接字工廠
規(guī)范用于與該可激活對(duì)象進(jìn)行通訊。
getID 方法返回對(duì)象的激活標(biāo)識(shí)符。該方法是受保護(hù)的,因而只有子類(lèi)才能獲取
對(duì)象的標(biāo)識(shí)符。 對(duì)象的標(biāo)識(shí)符用于報(bào)告對(duì)象的非活動(dòng)狀態(tài)或注銷(xiāo)對(duì)象的激活描述
符。
register 方法為可激活的遠(yuǎn)程對(duì)象向激活系統(tǒng)注冊(cè)對(duì)象描述符 desc,從而使該
對(duì)象能在需要時(shí)被激活。該方法可用于注冊(cè)可激活對(duì)象而無(wú)需先創(chuàng)建該對(duì)象。它
返回可激活對(duì)象的 Remote stub,因此可加以保存并在今后調(diào)用,從而強(qiáng)制首次
創(chuàng)建/激活該對(duì)象。如果沒(méi)有向激活系統(tǒng)注冊(cè) desc 中的組標(biāo)識(shí)符,該方法將拋出
UnknownGroupException。如果激活系統(tǒng)未運(yùn)行,則拋出 ActivationException
。最后,如果對(duì)激活系統(tǒng)的遠(yuǎn)程調(diào)用失敗,則拋出 RemoteException。
inactive 方法用于通知系統(tǒng)具有相應(yīng)激活 id 的對(duì)象當(dāng)前是非活動(dòng)的。如果已知
該對(duì)象當(dāng)前是活動(dòng)的,則該對(duì)象將不從 RMI 運(yùn)行時(shí)環(huán)境中導(dǎo)出(僅在沒(méi)有待定的
或執(zhí)行的調(diào)用時(shí)),從而可不再接收到來(lái)的調(diào)用。該調(diào)用還將通知該虛擬機(jī)的 A
ctivationGroup 該對(duì)象處于非活動(dòng)狀態(tài);而該組又將通知其 ActivationMonito
r。如果該調(diào)用成功,則此后對(duì)激活器的激活請(qǐng)求將導(dǎo)致重新激活該對(duì)象。如果成
功地阻止該對(duì)象被導(dǎo)出(意味著此時(shí)它沒(méi)有待定或執(zhí)行調(diào)用),則 inactive 方
法返回 true;如果由于待定或進(jìn)程內(nèi)調(diào)用而不能阻止該對(duì)象被導(dǎo)出,則返回 fa
lse。如果對(duì)象是未知的(它可能是非活動(dòng)的),則該方法將拋出 UnknownObjec
tException;如果組是非活動(dòng)的,則拋出 ActivationException;如果通知顯示
器的調(diào)用失敗,則拋出 RemoteException。如果該對(duì)象被認(rèn)為是活動(dòng)的但已自己
阻止導(dǎo)出,則該操作仍將成功進(jìn)行。
unregister 方法用于撤消與 id 關(guān)聯(lián)的激活描述符的先前注冊(cè)。對(duì)象不能再用這
個(gè) id 來(lái)激活。如果該對(duì)象 id 對(duì)激活系統(tǒng)來(lái)說(shuō)是未知的,則拋出 UnknownObje
ctException。如果激活系統(tǒng)未處于運(yùn)行狀態(tài),則拋出 ActivationException。如
果對(duì)激活系統(tǒng)的遠(yuǎn)程調(diào)用失敗,則拋出 RemoteException。
第一個(gè) exportObject 方法可被“可激活”但不擴(kuò)展 Activatable 類(lèi)的對(duì)象顯式
調(diào)用,其目的是:a) 向激活系統(tǒng)注冊(cè)對(duì)象的激活描述符 desc,由所提供的 cod
ebase 和 data 構(gòu)造(因此可激活該對(duì)象);b) 從指定 port 導(dǎo)出遠(yuǎn)程對(duì)象 ob
j(如果該 port 為零,則將選擇匿名端口)。對(duì)象一旦被導(dǎo)出,即可接收到來(lái)的
調(diào)用。
該 exportObject 方法返回向激活系統(tǒng)注冊(cè)描述符 desc 時(shí)所獲得的激活標(biāo)識(shí)符
。如果在虛擬機(jī)中激活組不是活動(dòng)的,則拋出 ActivationException。如果對(duì)象
注冊(cè)或?qū)С鍪?,則拋出 RemoteException。
如果 obj 擴(kuò)展 Activatable,則不必調(diào)用該方法,因?yàn)榈谝粋€(gè) Activatable 構(gòu)
造函數(shù)將調(diào)用該方法。
第二個(gè) exportObject 方法與第一個(gè)相同,但它允許將客戶(hù)機(jī)和服務(wù)器套接字工
廠規(guī)范用于與該可激活對(duì)象進(jìn)行通訊。
第三個(gè) exportObject 方法將帶標(biāo)識(shí)符 id 的“可激活”遠(yuǎn)程對(duì)象(不一定是 A
ctivatable 類(lèi)型的)導(dǎo)出到 RMI 運(yùn)行時(shí),以使對(duì)象 obj 能夠接收到來(lái)的調(diào)用。
如果 port 為零,則將在某個(gè)匿名端口導(dǎo)出該對(duì)象。
激活時(shí),不擴(kuò)展 Activatable 類(lèi)的“可激活”對(duì)象應(yīng)顯式地調(diào)用此 exportObje
ct 方法。確實(shí)擴(kuò)展 Activatable 類(lèi)的對(duì)象不必直接調(diào)用該方法;它將被上面的
第三個(gè)構(gòu)造函數(shù)所調(diào)用(應(yīng)從其專(zhuān)用的激活構(gòu)造函數(shù)中調(diào)用子類(lèi))。
該 exportObject 方法將返回可激活對(duì)象的 Remote stub。如果該對(duì)象的導(dǎo)出失
敗,則該方法將拋出 RemoteException。
第四個(gè) exportObject 方法與第三個(gè)相同,但它允許將客戶(hù)機(jī)和服務(wù)器套接字工
廠規(guī)范用于與該可激活對(duì)象進(jìn)行通訊。
unexportObject 方法使遠(yuǎn)程對(duì)象 obj 不能接收到來(lái)的調(diào)用。如果參數(shù) force 為
true,則即使有對(duì)遠(yuǎn)程對(duì)象的待定調(diào)用或遠(yuǎn)程對(duì)象在進(jìn)程內(nèi)仍有調(diào)用,對(duì)象也將
被強(qiáng)制阻止導(dǎo)出。如果參數(shù) force 為 false,則只在沒(méi)有對(duì)對(duì)象的待定調(diào)用或進(jìn)
程內(nèi)沒(méi)有調(diào)用時(shí)它才被阻止導(dǎo)出。如果成功地阻止了該對(duì)象的導(dǎo)出,則 RMI 運(yùn)行
時(shí)將從其內(nèi)部表中刪掉它。使用這種強(qiáng)制方式從 RMI 刪除對(duì)象可能會(huì)使客戶(hù)機(jī)持
有遠(yuǎn)程對(duì)象的過(guò)時(shí)遠(yuǎn)程引用。如果此前沒(méi)有將對(duì)象導(dǎo)出到 RMI 運(yùn)行時(shí),則該方法
將拋出 java.rmi.NoSuchObjectException。
構(gòu)造可激活的遠(yuǎn)程對(duì)象
為了使對(duì)象可激活,“可激活”對(duì)象實(shí)現(xiàn)類(lèi)不管是否擴(kuò)展 Activatable 類(lèi),都必
須定義一個(gè)特殊的公共構(gòu)造函數(shù)。該公共構(gòu)造函數(shù)帶有兩個(gè)參數(shù):激活標(biāo)識(shí)符(
類(lèi)型為 ActivationID)及激活數(shù)據(jù) java.rmi.MarshalledObject(在注冊(cè)時(shí)所用
的激活描述符中提供)。當(dāng)激活組在其虛擬機(jī)內(nèi)激活某個(gè)遠(yuǎn)程對(duì)象時(shí),它將利用
此特殊構(gòu)造函數(shù)來(lái)構(gòu)造對(duì)象(后面將作詳細(xì)說(shuō)明)。遠(yuǎn)程對(duì)象實(shí)現(xiàn)可適當(dāng)用激活
數(shù)據(jù)來(lái)初始化自己。遠(yuǎn)程對(duì)象也可能想保留其激活標(biāo)識(shí)符,這樣就可以在它變?yōu)?nbsp;
非活動(dòng)狀態(tài)(通過(guò)對(duì) Activatable. inactive 方法的調(diào)用)時(shí)通知激活組。
Activatable 構(gòu)造函數(shù)的第一種和第二種形式用于從指定的 port 注冊(cè)并導(dǎo)出可
激活對(duì)象。最初構(gòu)造對(duì)象時(shí)應(yīng)使用該構(gòu)造函數(shù);該構(gòu)造函數(shù)的第三種形式將在重
新激活對(duì)象時(shí)使用。
Activatable 的具體子類(lèi)必須在最初構(gòu)造期間調(diào)用第一種或第二種構(gòu)造函數(shù)以注
冊(cè)并導(dǎo)出對(duì)象。 構(gòu)造函數(shù)首先用對(duì)象的類(lèi)名創(chuàng)建一個(gè)激活描述符 (ActivationD
esc)、對(duì)象所提供的 codebase 和 data(其激活組為虛擬機(jī)的缺省激活組)。然
后,構(gòu)造函數(shù)將向缺省的 ActivationSystem 注冊(cè)該描述符。最后,構(gòu)造函數(shù)在
特定 port 上(如果 port 為零,則選擇匿名端口)將可激活對(duì)象導(dǎo)出到 RMI 運(yùn)
行時(shí)中,并將該對(duì)象作為 activeObject 報(bào)告給本地 ActivationGroup。如果在
注冊(cè)或?qū)С龅倪^(guò)程中出錯(cuò),則構(gòu)造函數(shù)拋出 RemoteException。注意,構(gòu)造函數(shù)
也初始化它的 ActivationID(通過(guò)注冊(cè)獲得),因此接下來(lái)對(duì) protected 方法
getID 的調(diào)用將返回對(duì)象的激活標(biāo)識(shí)符。
Activatable 構(gòu)造函數(shù)的第三種形式用于從指定的端口導(dǎo)出對(duì)象。當(dāng) Activatab
le 的具體子類(lèi)被對(duì)象自己的“激活”構(gòu)造函數(shù)激活時(shí),必須調(diào)用第三種構(gòu)造函數(shù)
。該“激活”構(gòu)造函數(shù)帶兩個(gè)參數(shù):
對(duì)象的 ActivationID
對(duì)象的初始化數(shù)據(jù),一個(gè) MarshalledObject 對(duì)象
該構(gòu)造函數(shù)只將可激活對(duì)象從特定 port(如果 port 為零,則選擇匿名端口)導(dǎo)
出到 RMI 運(yùn)行時(shí)中,而并不通知 ActivationGroup 該對(duì)象已是活動(dòng)對(duì)象。因?yàn)?nbsp;
正是 ActivationGroup 激活該對(duì)象的,因而它自然知道對(duì)象已處活動(dòng)狀態(tài)。
下面是遠(yuǎn)程對(duì)象接口 Server 和擴(kuò)展 Activatable 類(lèi)的實(shí)現(xiàn) ServerImpl 的示例:
package examples;
public interface Server extends java.rmi.Remote
{
public void doImportantStuff()
throws java.rmi.RemoteException;
}
public class ServerImpl extends Activatable implements Server
{
// 初始構(gòu)造、注冊(cè)及導(dǎo)出時(shí)的構(gòu)造函數(shù)
public ServerImpl(String codebase, MarshalledObject data)
throws ActivationException, java.rmi.RemoteException
{
// 向激活系統(tǒng)注冊(cè)對(duì)象,然后
// 在匿名端口上導(dǎo)出
super(codebase, data, false, 0);
}
// 激活及導(dǎo)出的構(gòu)造函數(shù)。該構(gòu)造函數(shù)由
// ActivationInstantiator.newInstance
// 方法在激活過(guò)程中所調(diào)用,以構(gòu)造對(duì)象
public ServerImpl(ActivationID id, MarshalledObject data)
throws java.rmi.RemoteException
{
// 調(diào)用父類(lèi)的構(gòu)造函數(shù)以
// 將對(duì)象導(dǎo)出到 RMI 運(yùn)行時(shí)。
super(id, 0);
// 初始化對(duì)象(例如利用數(shù)據(jù))
}
public void doImportantStuff() { ... }
}
對(duì)象將負(fù)責(zé)導(dǎo)出自己。Activatable 的構(gòu)造函數(shù)負(fù)責(zé)將對(duì)象導(dǎo)出到具有活動(dòng)引用
類(lèi)型 UnicastRemoteObject 的 RMI 運(yùn)行時(shí)中,因此,擴(kuò)展 Activatable 的對(duì)象
實(shí)現(xiàn)不必關(guān)心顯式導(dǎo)出對(duì)象(不是調(diào)用相應(yīng)的超類(lèi)構(gòu)造函數(shù))的具體細(xì)節(jié)。如果
對(duì)象實(shí)現(xiàn)不擴(kuò)展類(lèi) Activatable,則該對(duì)象必須通過(guò)調(diào)用某個(gè) Activatable.exp
ortObject 靜態(tài)方法來(lái)顯式導(dǎo)出該對(duì)象。
下例中,ServerImpl 不擴(kuò)展 Activatable,而是擴(kuò)展另一個(gè)類(lèi)。因此,ServerI
mpl 負(fù)責(zé)在初始構(gòu)造和激活過(guò)程中導(dǎo)出自己。下述的類(lèi)定義給出了 ServerImpl
的初始化構(gòu)造函數(shù)及其特殊“激活”構(gòu)造函數(shù),以及每個(gè)構(gòu)造函數(shù)內(nèi)用于導(dǎo)出對(duì)
象的相應(yīng)調(diào)用:
package examples;
public class ServerImpl extends SomeClass implements Server
{
// 初始創(chuàng)建時(shí)的構(gòu)造函數(shù)
public ServerImpl(String codebase, MarshalledObject data)
throws ActivationException, java.rmi.RemoteException
{
// 注冊(cè)并導(dǎo)出對(duì)象
Activatable.exportObject(this, codebase, data, false, 0);
}
// 激活的構(gòu)造函數(shù)
public ServerImpl(ActivationID id, MarshalledObject data)
throws java.rmi.RemoteException
{
// 導(dǎo)出對(duì)象
Activatable.exportObject(this, id, 0);
}
public void doImportantStuff() { ... }
}
在不創(chuàng)建對(duì)象的情況下注冊(cè)激活描述符
要在不創(chuàng)建對(duì)象的情況下向激活系統(tǒng)注冊(cè)可激活遠(yuǎn)程對(duì)象,程序員只需為對(duì)象注
冊(cè)激活描述符(類(lèi) ActivationDesc 的實(shí)例)。激活描述符含有一切所需的信息
,因此必要時(shí)激活系統(tǒng)就可以激活該對(duì)象。可用以下方法來(lái)注冊(cè)類(lèi) examples.Se
rverImpl 實(shí)例的激活描述符(忽略異常處理):
Server server;ActivationDesc desc;String codebase = "http://zaphod/cod
ebase/";
MarshalledObject data = new MarshalledObject("some data");desc = new A
ctivationDesc( "examples.ServerImpl", codebase, data);server = (Server
)Activatable.register(desc);
register 調(diào)用將返回一個(gè) Remote stub(它是 examples.ServerImpl 對(duì)象的 s
tub),并實(shí)現(xiàn)一組與 examples.ServerImpl 所實(shí)現(xiàn)的遠(yuǎn)程接口相同的遠(yuǎn)程接口
(即 stub 實(shí)現(xiàn)遠(yuǎn)程接口 Server)。該 stub 對(duì)象(上述被強(qiáng)制類(lèi)型轉(zhuǎn)換并指派
給 server 的對(duì)象)可作為參數(shù)傳給期望實(shí)現(xiàn) examples.Server 遠(yuǎn)程接口的對(duì)象
的任何方法調(diào)用。
7.4 激活接口
在 RMI 激活協(xié)議中,為使系統(tǒng)運(yùn)轉(zhuǎn)正常,激活器必須保證以下兩點(diǎn):
象所有的系統(tǒng)守護(hù)進(jìn)程一樣,計(jì)算機(jī)處于打開(kāi)狀態(tài)時(shí)激活器必須保持運(yùn)行狀態(tài)
激活器不能重新激活已處在活動(dòng)狀態(tài)的遠(yuǎn)程對(duì)象。
激活器將為它所要激活的組和對(duì)象維護(hù)一個(gè)相應(yīng)的信息數(shù)據(jù)庫(kù)。
7.4.1 激活器接口
激活器是參與激活進(jìn)程的實(shí)體之一。如前所述,stub 內(nèi)的不完善引用將通過(guò)調(diào)用
激活器的 activate 方法來(lái)獲得對(duì)可激活遠(yuǎn)程對(duì)象的“活”引用。激活器接到激
活請(qǐng)求后,就開(kāi)始查找該激活標(biāo)識(shí)符 id 的激活描述符,以決定要在哪個(gè)組中激
活對(duì)象,然后調(diào)用激活組的實(shí)例化器的newInstance 方法(ActivationGroup 的
遠(yuǎn)程接口將在后面說(shuō)明)。激活器將根據(jù)需要啟動(dòng)激活組的執(zhí)行過(guò)程。例如,如
果給定的組描述符的激活組還未運(yùn)行,則激活器將為該激活組生成一個(gè)子虛擬機(jī)
,以便在該新虛擬機(jī)中建立該組。
激活器將負(fù)責(zé)監(jiān)控和檢測(cè)激活組何時(shí)失敗,以便將過(guò)時(shí)的遠(yuǎn)程引用從其內(nèi)部表中
刪去。
package java.rmi.activation;
public interface Activator extends java.rmi.Remote
{
java.rmi.MarshalledObject activate(ActivationID id, boolean force)
throws UnknownObjectException, ActivationException,
java.rmi.RemoteException;
}
activate 方法激活與激活標(biāo)識(shí)符 id 所關(guān)聯(lián)的對(duì)象。如果激活器知道對(duì)象已經(jīng)為
活動(dòng)對(duì)象,且 force 參數(shù)為 false,就會(huì)立即將含有“活”引用的 stub 返給調(diào)
用程序;如果激活器不知道相應(yīng)的遠(yuǎn)程對(duì)象是活動(dòng)的或 force 參數(shù)為 true,則
激活器將利用激活描述符信息(先前已為獲得 id 而注冊(cè)過(guò))來(lái)決定對(duì)象應(yīng)該在
哪個(gè)組(虛擬機(jī))中被激活。如果對(duì)象組的相應(yīng)激活 Instantiator 已經(jīng)存在,
則激活器將通過(guò)傳遞 id 和對(duì)象的激活描述符來(lái)調(diào)用該激活實(shí)例化器的newInsta
nce 方法。
如果對(duì)象組描述符的激活實(shí)例化器(組)還不存在,則激活器將啟動(dòng)新的 Activ
ationInstantiator 化身執(zhí)行進(jìn)程(例如通過(guò)生成子進(jìn)程)。當(dāng)激活器為某一組
重建 ActivationInstantiator 時(shí),它必須將該組的化身數(shù)增一。注意,化身數(shù)
從 0 開(kāi)始。激活系統(tǒng)用化身數(shù)來(lái)檢測(cè)后來(lái)的 ActivationSystem.activeGroup 和
ActivationMonitor.inactiveGroup 調(diào)用。激活系統(tǒng)將棄去那些化身數(shù)小于組的
當(dāng)前數(shù)的調(diào)用。
----------------------------------------------------------------------
----------
注意 - 激活器在啟動(dòng)新的激活組時(shí)必須與激活組的標(biāo)識(shí)符、描述符及化身數(shù)進(jìn)行
通訊。激活器將在一個(gè)獨(dú)立的虛擬機(jī)中(例如作為一個(gè)獨(dú)立的進(jìn)程或子進(jìn)程)生
成激活組。因此,它必須將信息傳遞過(guò)去,以指定用 ActivationGroup.createG
roup 方法來(lái)創(chuàng)建該組時(shí)所需的信息。激活器并未指定如何將此信息傳給所生成的
進(jìn)程??捎靡丫幗M對(duì)象的形式將此信息送到子進(jìn)程的標(biāo)準(zhǔn)輸入中。
----------------------------------------------------------------------
----------
當(dāng)激活器接收到激活組的回調(diào)(通過(guò) ActivationSystem.activeGroup 方法,該
回調(diào)可指明激活組的引用和化身數(shù))時(shí),激活器就可以調(diào)用該激活實(shí)例化器的 n
ewInstance 方法,從而將每個(gè)待定的激活請(qǐng)求轉(zhuǎn)發(fā)給該激活實(shí)例化器,同時(shí)將結(jié)
果(一個(gè)已編組遠(yuǎn)程對(duì)象引用、一個(gè) stub)返給每個(gè)調(diào)用程序。
注意,激活器接收的是 MarshalledObject 對(duì)象而不是 Remote 對(duì)象。因此,激
活器不需要加載該對(duì)象的代碼,也不需要參與該對(duì)象的分布式垃圾收集。如果激
活器保留了對(duì)遠(yuǎn)程對(duì)象的強(qiáng)引用,則該激活器將防止該對(duì)象在正常的分布式垃圾
收集機(jī)制下被當(dāng)作垃圾而收集。
如果激活失敗,activate 方法將拋出 ActivationException。激活可能會(huì)因以下
各種原因而失?。赫也坏筋?lèi)、無(wú)法與激活組取得聯(lián)系等。如果先前沒(méi)有為激活標(biāo)
識(shí)符 id 向該激活器注冊(cè)激活描述符,則 activate 方法將拋出 UnknownObject
Exception。如果對(duì)該激活器的遠(yuǎn)程調(diào)用失敗,則拋出 RemoteException。
7.4.2 ActivationSystem 接口
ActivationSystem 提供了一種為組和可激活對(duì)象(這些對(duì)象將在這些組中被激活
)注冊(cè)的方法。 ActivationSystem 與 Activator 和 ActivationMonitor 都能
密切合作。前者負(fù)責(zé)激活通過(guò) ActivationSystem 所注冊(cè)的對(duì)象;后者負(fù)責(zé)獲取
活動(dòng)對(duì)象、非活動(dòng)對(duì)象及非活動(dòng)組的有關(guān)信息。
package java.rmi.activation;
public interface ActivationSystem extends java.rmi.Remote
{
public static final int SYSTEM_PORT = 1098;
ActivationGroupID registerGroup(ActivationGroupDesc desc)
throws ActivationException, java.rmi.RemoteException;
ActivationMonitor activeGroup(ActivationGroupID id,
ActivationInstantiator group,
long incarnation)
throws UnknownGroupException, ActivationException,
java.rmi.RemoteException;
void unregisterGroup(ActivationGroupID id)
throws ActivationException, UnknownGroupException,
java.rmi.RemoteException;
ActivationID registerObject(ActivationDesc desc)
throws ActivationException, UnknownGroupException,
java.rmi.RemoteException;
void unregisterObject(ActivationID id)
throws ActivationException, UnknownObjectException,
java.rmi.RemoteException;
void shutdown() throws java.rmi.RemoteException;
}
----------------------------------------------------------------------
----------
注意 - 作為一種安全措施,以上所有方法(registerGroup、activeGroup、unr
egisterGroup、registerObject、unregisterObject 和 shutdown)如果被客戶(hù)
機(jī)所調(diào)用,且該客戶(hù)機(jī)所處主機(jī)與激活系統(tǒng)不同,則將拋出 java.rmi.AccessEx
ception。該異常是 java.rmi.RemoteException 的子類(lèi)。
----------------------------------------------------------------------
----------
registerObject 方法用來(lái)注冊(cè)激活描述符 desc,同時(shí)也為可激活遠(yuǎn)程對(duì)象獲取
激活標(biāo)識(shí)符。 ActivationSystem 為描述符 desc 所指定的對(duì)象創(chuàng)建 Activatio
nID(激活標(biāo)識(shí)符),并將激活描述符及其關(guān)聯(lián)的標(biāo)識(shí)符記錄在穩(wěn)定的存儲(chǔ)庫(kù)中以
備將來(lái)使用。當(dāng) Activator 接到某個(gè)特定標(biāo)識(shí)符的 activate 請(qǐng)求時(shí),它就查找
該指定標(biāo)識(shí)符的激活描述符(先前已注冊(cè)),并用此信息來(lái)激活該對(duì)象。如果 d
esc 中所引用的組并沒(méi)有向該系統(tǒng)注冊(cè),則該方法將拋出 UnknownGroupExcepti
on。如果注冊(cè)失?。ɡ?,數(shù)據(jù)庫(kù)更新失敗等),則拋出 ActivationException
。如果遠(yuǎn)程調(diào)用失敗, 則拋出 RemoteException。
unregisterObject 方法用于刪除激活標(biāo)識(shí)符 id 及以前向 ActivationSystem 注
冊(cè)過(guò)的相關(guān)描述符。該調(diào)用完成后,就不能再用對(duì)象的激活 id 來(lái)激活該對(duì)象。
如果對(duì)象的 id 是未知的(沒(méi)有被注冊(cè)),則該方法將拋出 UnknownObjectExce
ption。如果注銷(xiāo)失?。ɡ?,數(shù)據(jù)庫(kù)的更新失敗等),則該方法將拋出 Activa
tionException。如果遠(yuǎn)程調(diào)用失敗,則拋出 RemoteException。
registerGroup 方法用于向激活系統(tǒng)注冊(cè)組描述符 desc 所指定的激活組,并返
回指派給該組的 ActivationGroupID。必須先向 ActivationSystem 注冊(cè)激活組
,然后才能在該組中注冊(cè)對(duì)象。 如果組的注冊(cè)失敗,則該方法將拋出 Activati
onException。如果遠(yuǎn)程調(diào)用失敗,則拋出 RemoteException。
activeGroup 方法是來(lái)自 ActivationGroup(具有標(biāo)識(shí)符 id)的回調(diào),用以通知
激活系統(tǒng)下列信息:組現(xiàn)在是活動(dòng)的,而且也是該虛擬機(jī)的 ActivationInstant
iator。此回調(diào)是在 ActivationGroup.createGroup 方法內(nèi)部進(jìn)行的,可以獲取
ActivationMonitor。組將用該 ActivationMonitor 就對(duì)象和組的狀態(tài)(即該組
內(nèi)的組和對(duì)象已變?yōu)榉腔顒?dòng)的)對(duì)系統(tǒng)進(jìn)行更新。 如果該組沒(méi)有被注冊(cè),則拋出
UnknownGroupException。如果該組已是活動(dòng)的,則拋出 ActivationException
。如果對(duì)激活系統(tǒng)的遠(yuǎn)程調(diào)用失敗,則拋出 RemoteException。
unregisterGroup 方法將具有標(biāo)識(shí)符 id 的激活組從激活系統(tǒng)中刪掉。激活組將
進(jìn)行此回調(diào),以通知激活器應(yīng)該將該組銷(xiāo)毀。如果此調(diào)用順利完成,就將無(wú)法再
在該組內(nèi)注冊(cè)和激活對(duì)象。有關(guān)該組及其相關(guān)對(duì)象的所有信息都將從系統(tǒng)中刪掉
。如果該組是未經(jīng)注冊(cè)的,則該方法將拋出 UnknownGroupException。如果遠(yuǎn)程
調(diào)用失敗,則拋出 RemoteException。如果注銷(xiāo)失?。ㄈ鐢?shù)據(jù)庫(kù)更新失敗等),
則拋出 ActivationException。
shutdown 方法將以適當(dāng)?shù)漠惒椒绞浇K止激活系統(tǒng)和所有有關(guān)的激活進(jìn)程(激活器
、監(jiān)控器及組)。由激活守護(hù)進(jìn)程所生成的所有組都將被銷(xiāo)毀,激活守護(hù)進(jìn)程也
將退出。要關(guān)閉激活系統(tǒng)守護(hù)進(jìn)程 rmid,請(qǐng)執(zhí)行命令:
rmid -stop [-端口號(hào)]
該命令將關(guān)閉指定端口上的激活守護(hù)進(jìn)程(如果沒(méi)有指定端口,則將關(guān)閉缺省端
口上的守護(hù)進(jìn)程)。
7.4.3 ActivationMonitor 類(lèi)
ActivationMonitor 是 ActivationGroup 特有的,它可通過(guò)調(diào)用 ActivationSy
stem.activeGroup 以報(bào)告某個(gè)組時(shí)獲得(這種調(diào)用是在 ActivationGroup.crea
teGroup 方法內(nèi)部進(jìn)行的)。激活組在出現(xiàn)以下情況時(shí)負(fù)責(zé)通知 ActivationMon
itor:它的對(duì)象已變成活動(dòng)對(duì)象、非活動(dòng)對(duì)象或該組已整個(gè)變成非活動(dòng)。
package java.rmi.activation;
public interface ActivationMonitor extends java.rmi.Remote
{
public abstract void inactiveObject(ActivationID id)
throws UnknownObjectException, RemoteException;
public void activeObject(ActivationID id,
java.rmi.MarshalledObject mobj)
throws UnknownObjectException, java.rmi.RemoteException;
public void inactiveGroup(ActivationGroupID id, long incarnation)
throws UnknownGroupException, java.rmi.RemoteException;
}
當(dāng)激活組中的某個(gè)對(duì)象變成非活動(dòng)(停用)時(shí),該激活組將調(diào)用其監(jiān)控器的 ina
ctiveObject 方法。激活組通過(guò)調(diào)用它的 inactiveObject 方法來(lái)發(fā)現(xiàn)其虛擬機(jī)
中的對(duì)象(該對(duì)象參與了激活)是否已為非活動(dòng)狀態(tài)。
inactiveObject 調(diào)用將通知 ActivationMonitor 其所保留的、具有激活標(biāo)識(shí)符
id 的對(duì)象的遠(yuǎn)程對(duì)象引用已不再有效。監(jiān)控器將把與 id 關(guān)聯(lián)的引用視為已過(guò)
時(shí)。由于該引用被當(dāng)成過(guò)時(shí)引用,因此后面為同一激活標(biāo)識(shí)符所進(jìn)行的 activat
e 調(diào)用將導(dǎo)致遠(yuǎn)程對(duì)象被重新激活。如果該對(duì)象對(duì) ActivationMonitor 未知,該
方法將拋出 UnknownObjectException。如果遠(yuǎn)程調(diào)用失敗,則拋出 RemoteExce
ption。
activeObject 調(diào)用通知 ActivationMonitor 與 id 相關(guān)聯(lián)的對(duì)象現(xiàn)在是活動(dòng)的
。參數(shù) obj 是該對(duì)象的 stub 的編組表述。 如果組中的某個(gè)對(duì)象是通過(guò)其它方
法被激活的,而不是由系統(tǒng)直接激活的(也就是說(shuō),對(duì)象被注冊(cè)并自己“激活”
自己),則 ActivationGroup 必須通知其監(jiān)控器。如果該對(duì)象的標(biāo)識(shí)符先前沒(méi)有
被注冊(cè),則該方法將拋出 UnknownObjectException。如果遠(yuǎn)程調(diào)用失敗,則拋出
RemoteException。
inactiveGroup 調(diào)用通知監(jiān)控器由 id 和 incarnation 所指定的組現(xiàn)在已非活動(dòng)
。一旦下一個(gè)要求在該組內(nèi)激活對(duì)象的請(qǐng)求出現(xiàn)時(shí),將用一個(gè)更大的化身數(shù)來(lái)重
新創(chuàng)建該組。當(dāng)組中所有對(duì)象都報(bào)告說(shuō)它們已非活動(dòng)對(duì)象時(shí),該組即變成非活動(dòng)
組。如果該組的 id 沒(méi)有被注冊(cè),或者化身數(shù)比該組當(dāng)前的化身數(shù)更小,則該方
法將拋出 UnknownGroupException。如果遠(yuǎn)程調(diào)用失敗,則拋出 RemoteExcepti
on。
7.4.4 ActivationInstantiator 類(lèi)
ActivationInstantiator 負(fù)責(zé)創(chuàng)建可激活對(duì)象的實(shí)例。ActivationGroup 的具體
子類(lèi)實(shí)現(xiàn) newInstance 方法,以便對(duì)在組內(nèi)創(chuàng)建對(duì)象的過(guò)程進(jìn)行控制。
package java.rmi.activation;
public interface ActivationInstantiator extends java.rmi.Remote
{
public MarshalledObject newInstance(ActivationID id,
ActivationDesc desc)
throws ActivationException, java.rmi.RemoteException;
}
為了在該組內(nèi)重新創(chuàng)建具有激活標(biāo)識(shí)符 id、描述符 desc 的對(duì)象,激活器需要調(diào)
用實(shí)例化器的 newInstance 方法。實(shí)例化器負(fù)責(zé):
用描述符的 getClassName 方法來(lái)決定對(duì)象的類(lèi);
從由描述符中所獲得的 cadebase 路徑中加載對(duì)象的類(lèi)(用 getLocation 方法)
;
通過(guò)調(diào)用對(duì)象的類(lèi)的特殊“激活”構(gòu)造函數(shù)創(chuàng)建該類(lèi)的實(shí)例。這種特殊構(gòu)造函數(shù)
帶有兩個(gè)參數(shù):一個(gè)是對(duì)象的 ActivationID,另一個(gè)是含有對(duì)象特有的初始化數(shù)
據(jù)的 MarshalledObject;
返回一個(gè)含有它所創(chuàng)建的遠(yuǎn)程對(duì)象的 MarshalledObject。
實(shí)例化器還負(fù)責(zé)在它所創(chuàng)建或激活的對(duì)象不再是活動(dòng)對(duì)象時(shí)進(jìn)行報(bào)告,因此可以
對(duì)其 ActivationMonitor 執(zhí)行相應(yīng)的 inactiveObject 調(diào)用(詳細(xì)信息,參見(jiàn)
ActivationGroup 類(lèi))。
如果對(duì)象的激活失敗, newInstance 方法將拋出 ActivationException。如果遠(yuǎn)
程調(diào)用失敗,則該方法將拋出 RemoteException。
7.4.5 ActivationGroupDesc 類(lèi)
激活組描述符 ActivationGroupDesc 含有創(chuàng)建或重新創(chuàng)建激活組(將在該激活組
中激活相同 Java 虛擬機(jī)上的對(duì)象)所需的信息。
這種描述符含有:
組的類(lèi)名,
組的 cadebase 路徑(組的類(lèi)所在位置),
“已編組”對(duì)象,它可包含對(duì)象特定的初始化數(shù)據(jù)。
對(duì)象的類(lèi)必須是 ActivationGroup 的具體子類(lèi)。ActivationGroup 的子類(lèi)是用
ActivationGroup.createGroup 靜態(tài)方法來(lái)創(chuàng)建或重新創(chuàng)建的,該靜態(tài)方法將調(diào)
用含有以下兩個(gè)參數(shù)的特殊構(gòu)造函數(shù):
該組的 ActivationGroupID,
該組的初始化數(shù)據(jù)(在 java.rmi.MarshalledObject 中)
package java.rmi.activation;
public final class ActivationGroupDesc implements java.io.Serializable
{
public ActivationGroupDesc(java.util.Properties props,
CommandEnvironment env);;
public ActivationGroupDesc(String className,
String codebase,
java.rmi.MarshalledObject data,
java.util.Properties props,
CommandEnvironment env);
public String getClassName();
public String getLocation();
public java.rmi.MarshalledObject getData();
public CommandEnvironment getCommandEnvironment();
public java.util.Properties getPropertiesOverrides();
}
第一個(gè)構(gòu)造函數(shù)將創(chuàng)建一個(gè)組描述符,它用系統(tǒng)的缺省值來(lái)作為組的實(shí)現(xiàn)和代碼
位置。各屬性指定了 Java 環(huán)境覆蓋(它將覆蓋組實(shí)現(xiàn)虛擬機(jī)中的系統(tǒng)屬性)。
命令環(huán)境可控制啟動(dòng)子虛擬機(jī)時(shí)所用的確切命令/選項(xiàng),也可為 null 以接受 rm
id 的缺省值。
第二個(gè)構(gòu)造函數(shù)和第一個(gè)相同,但它允許指定 Properties 和 CommandEnvironm
ent。
getClassName 方法返回組的類(lèi)名。
getLocation 方法返回 cadebase 路徑,從中可加載該組的類(lèi)。
getData 方法以編組形式返回組的初始化數(shù)據(jù)。
getCommandEnvironment 方法返回命令環(huán)境(可能為 null)。
getPropertiesOverrides 方法返回該描述符的屬性覆蓋(可能為 null)。
7.4.6 ActivationGroupDesc.CommandEnvironment 類(lèi)
CommandEnvironment 類(lèi)允許對(duì)缺省系統(tǒng)屬性進(jìn)行覆蓋,并可為 ActivationGrou
p 指定由實(shí)現(xiàn)所定義的選項(xiàng)。
public static class CommandEnvironment
implements java.io.Serializable
{
public CommandEnvironment(String cmdpath, String[] args);
public boolean equals(java.lang.Object);
public String[] getCommandOptions();
public String getCommandPath();
public int hashCode();
}
構(gòu)造函數(shù)將用所給的命令 cmdpath 和另一個(gè)命令行選項(xiàng) args 創(chuàng)建 CommandEnv
ironment。
equals 實(shí)現(xiàn)對(duì)命令環(huán)境對(duì)象的內(nèi)容等效操作。對(duì) hashCode 方法進(jìn)行適當(dāng)?shù)膶?shí)現(xiàn)
可在必要時(shí)將 CommandEnvironment 對(duì)象儲(chǔ)存在散列表中。
getCommandOptions 方法返回環(huán)境對(duì)象的命令行選項(xiàng)。
getCommandPath 方法返回環(huán)境對(duì)象的命令字符串。
7.4.7 ActivationGroupID 類(lèi)
注冊(cè)過(guò)的激活組的標(biāo)識(shí)符可有以下幾個(gè)用途:
在激活系統(tǒng)中對(duì)該組進(jìn)行唯一標(biāo)識(shí)
含有對(duì)該組的激活系統(tǒng)的引用,因而必要時(shí)該組能與其激活系統(tǒng)聯(lián)系。
ActivationGroupID 將在調(diào)用 ActivationSystem.registerGroup 時(shí)被返回,并
用來(lái)在該激活系統(tǒng)內(nèi)標(biāo)識(shí)該組。當(dāng)創(chuàng)建或重新創(chuàng)建激活組時(shí),該組標(biāo)識(shí)符將被作
為參數(shù)傳給激活組的特殊構(gòu)造函數(shù)。
package java.rmi.activation;
public class ActivationGroupID implements java.io.Serializable
{
public ActivationGroupID(ActivationSystem system);
public ActivationSystem getSystem();
public boolean equals(Object obj);
public int hashCode();
}
ActivationGroupID 構(gòu)造函數(shù)創(chuàng)建唯一的組標(biāo)識(shí)符。該標(biāo)識(shí)符的 ActivationSys
tem 是 system。
getSystem 方法返回組的激活系統(tǒng)。
hashCode 方法返回組標(biāo)識(shí)符的散列碼。兩個(gè)指向同一遠(yuǎn)程組的組標(biāo)識(shí)符將具有相
同的散列碼。
equals 方法比較兩個(gè)組標(biāo)識(shí)符內(nèi)容的等效性。如果以下兩個(gè)條件均成立,該方法
將返回 true: 1) 兩個(gè)唯一標(biāo)識(shí)符在內(nèi)容上等價(jià)。2) 各標(biāo)識(shí)符中指定的激活系
統(tǒng)都引用同一遠(yuǎn)程對(duì)象。
7.4.8 ActivationGroup 類(lèi)
ActivationGroup 負(fù)責(zé)在其組中創(chuàng)建“可激活”對(duì)象的新實(shí)例,并在出現(xiàn)下列情
況時(shí)通知其 ActivationMonitor: 其對(duì)象變成活動(dòng)或非活動(dòng),或者該組整體變成
非活動(dòng)。
ActivationGroup 最初是由以下方法之一創(chuàng)建的:
作為創(chuàng)建對(duì)象的“缺省” ActivationDesc 的副效應(yīng)而創(chuàng)建
通過(guò)對(duì) ActivationGroup.createGroup 方法的顯式調(diào)用而創(chuàng)建
作為在組(該組中僅 ActivationGroupDesc 被注冊(cè)過(guò))中激活第一個(gè)對(duì)象時(shí)的副
效應(yīng)而創(chuàng)建。
只有激活器才能重新創(chuàng)建 ActivationGroup。必要時(shí),激活器將為每個(gè)已注冊(cè)的
激活組生成一個(gè)獨(dú)立的虛擬機(jī)(例如作為子進(jìn)程)并將激活請(qǐng)求定向到相應(yīng)的組
。生成虛擬機(jī)的方式與實(shí)現(xiàn)有關(guān)。激活組是通過(guò) ActivationGroup.createGroup
靜態(tài)方法來(lái)創(chuàng)建的。createGroup 方法對(duì)即將創(chuàng)建的組有兩個(gè)要求: 1) 該組必
須是 ActivationGroup 的具體子類(lèi);2) 該組必須有一個(gè)取以下兩個(gè)參數(shù)的構(gòu)造
函數(shù):
該組的 ActivationGroupID,
該組的初始化數(shù)據(jù)(包含在 MarshalledObject中)
創(chuàng)建完畢,ActivationGroup 的缺省實(shí)現(xiàn)將在創(chuàng)建該組的 ActivationGroupDesc
時(shí)把系統(tǒng)屬性設(shè)置為強(qiáng)制系統(tǒng)屬性,并將安全管理器設(shè)置為 java.rmi.RMISecu
rityManager。如果應(yīng)用程序要求當(dāng)對(duì)象在組中被激活時(shí)設(shè)置某些特定的屬性,則
該應(yīng)用程序應(yīng)在創(chuàng)建 ActivationDesc 之前(缺省 ActivationGroupDesc 創(chuàng)建前
)設(shè)置這些屬性。
package java.rmi.activation;
public abstract class ActivationGroup
extends UnicastRemoteObject
implements ActivationInstantiator
{
protected ActivationGroup(ActivationGroupID groupID)
throws java.rmi.RemoteException;
public abstract MarshalledObject newInstance(ActivationID id,
ActivationDesc desc)
throws ActivationException, java.rmi.RemoteException;
public abstract boolean inactiveObject(ActivationID id)
throws ActivationException, UnknownObjectException,
java.rmi.RemoteException;
public static ActivationGroup createGroup(ActivationGroupID id,
ActivationGroupDesc desc,
long incarnation)
throws ActivationException;
public static ActivationGroupID currentGroupID();
public static void setSystem(ActivationSystem system)
throws ActivationException;
public static ActivationSystem getSystem()
throws ActivationException;
protected void activeObject(ActivationID id,
java.rmi.MarshalledObject mobj)
throws ActivationException, UnknownObjectException,
java.rmi.RemoteException;
protected void inactiveGroup()
throws UnknownGroupException, java.rmi.RemoteException;
}
激活器通過(guò)調(diào)用激活組的 newInstance 方法來(lái)激活具有激活描述符 desc 的對(duì)象
。激活組負(fù)責(zé):
利用描述符的 getClassName 方法來(lái)確定該對(duì)象的類(lèi);
通過(guò) getLocation 方法從由描述符中所得到的 URL 路徑中加載該類(lèi);
通過(guò)調(diào)用該對(duì)象類(lèi)的特殊構(gòu)造函數(shù)來(lái)創(chuàng)建該類(lèi)的實(shí)例。該構(gòu)造函數(shù)取以下兩個(gè)變
量:對(duì)象的 ActivationID 和含有對(duì)象初始化數(shù)據(jù)的 MarshalledObject;
將剛創(chuàng)建的遠(yuǎn)程對(duì)象的序列化版本返給激活器。
如果無(wú)法創(chuàng)建所給描述符的實(shí)例,該方法將拋出 ActivationException。
對(duì)該組的 inactiveObject 方法的調(diào)用是通過(guò)調(diào)用 Activatable.inactive 方法
來(lái)間接進(jìn)行的。當(dāng)遠(yuǎn)程對(duì)象停用時(shí)(該對(duì)象被認(rèn)為非活動(dòng)的),該對(duì)象的實(shí)現(xiàn)必
須調(diào)用 Activatable 的 inactive。如果對(duì)象在非活動(dòng)時(shí)不調(diào)用 Activatable.i
nactive,則該對(duì)象將永遠(yuǎn)不會(huì)被作為垃圾收集,因?yàn)榻M將對(duì)其所創(chuàng)建的對(duì)象保留
強(qiáng)引用。
組的 inactiveObject 方法可阻止從 RMI 運(yùn)行時(shí)中導(dǎo)出與 id 關(guān)聯(lián)的遠(yuǎn)程對(duì)象(
僅當(dāng)沒(méi)有對(duì)該對(duì)象的待定或正在執(zhí)行的調(diào)用時(shí))。使該對(duì)象將無(wú)法再接收到來(lái)的
RMI 調(diào)用。如果該對(duì)象當(dāng)前還有待定或正在執(zhí)行的調(diào)用,inactiveObject 將返
回 false 且不采取任何動(dòng)作。
如果 unexportObject 操作成功,意味著該對(duì)象沒(méi)有待定或正在執(zhí)行的調(diào)用。此
時(shí)組將通過(guò)監(jiān)控器的 inactiveObject 方法通知它的 ActivationMonitor 該遠(yuǎn)程
對(duì)象當(dāng)前是非活動(dòng)的,以便激活器在接到下一激活請(qǐng)求時(shí)即重新將該遠(yuǎn)程對(duì)象激
活。如果操作成功,inactiveObject 將返回 true。如果該對(duì)象被 ActivationG
roup 認(rèn)為是活動(dòng)的但已被阻止導(dǎo)出,操作將仍有可能成功。
如果激活組不知道該對(duì)象(例如該對(duì)象先前已被報(bào)告為是非活動(dòng)的,或者從未通
過(guò)該激活組來(lái)激活該對(duì)象),則 inactiveObject 方法將拋出 UnknownObjectEx
ception。如果非活動(dòng)操作失?。ɡ?,對(duì)激活器或激活組的遠(yuǎn)程調(diào)用失?。瑒t
將拋出 RemoteException。
createGroup 方法將為當(dāng)前虛擬機(jī)創(chuàng)建和設(shè)置激活組。只有在激活組是當(dāng)前未設(shè)
定的情況下才能對(duì)它進(jìn)行設(shè)置。當(dāng) Activator 為了執(zhí)行到來(lái)的 activate 請(qǐng)求而
啟動(dòng)某一激活組的重新創(chuàng)建過(guò)程時(shí),該激活組即通過(guò) createGroup 方法進(jìn)行設(shè)置
。組必須先向 ActivationSystem 注冊(cè)一個(gè)描述符,然后才能用該方法(將注冊(cè)
中得到的 ActivationID 傳給它)來(lái)創(chuàng)建該組。
由 ActivationGroupDesc(即 desc)指定的組必須是 ActivationGroup 的具體
子類(lèi)并具有公共構(gòu)造函數(shù)。該公共構(gòu)造函數(shù)取兩個(gè)參數(shù):一個(gè)是組的 Activatio
nGroupID;另一個(gè)是 MarshalledObject,它含有組的初始化數(shù)據(jù)(從組的Activ
ationGroupDesc 中獲得的)。注意: 如果應(yīng)用程序要?jiǎng)?chuàng)建自己的自定義激活組
,該組必須在構(gòu)造函數(shù)中設(shè)置安全管理器。否則將不能在該組中激活對(duì)象。
創(chuàng)建完組后,即通知 ActivationSystem 該組已通過(guò)調(diào)用 activeGroup 方法(該
方法將返回組的 ActivationMonitor)而被激活。應(yīng)用程序不必單獨(dú)調(diào)用 activ
eGroup,因?yàn)?nbsp;createGroup 方法將負(fù)責(zé)這一回調(diào)。
一旦組被創(chuàng)建,對(duì) currentGroupID 方法的后續(xù)調(diào)用都將返回該組的標(biāo)識(shí)符,直
到該組變成非活動(dòng)組為止。那時(shí),currentGroupID 方法將返回 null。
參數(shù) incarnation 表示當(dāng)前的組化身數(shù),也就是該組被激活的次數(shù)。一旦組被成
功創(chuàng)建,化身數(shù)就被用作 activeGroup 方法的參數(shù)。化身數(shù)從 0 開(kāi)始。如果該
組已經(jīng)存在,或在組的創(chuàng)建過(guò)程中出錯(cuò),createGroup 方法將拋出 ActivationE
xception。
setSystem 方法用于設(shè)置虛擬機(jī)的 ActivationSystem (system)。只有當(dāng)前沒(méi)有
組為活動(dòng)組時(shí)才能對(duì)激活系統(tǒng)進(jìn)行設(shè)置。如果沒(méi)有通過(guò)顯式調(diào)用 setSystem 來(lái)設(shè)
置激活系統(tǒng),則 getSystem 方法將嘗試通過(guò)在 Activator 的注冊(cè)服務(wù)程序中查
找名稱(chēng) java.rmi.activation.ActivationSystem 來(lái)獲得對(duì) ActivationSystem
的引用。缺省情況下,查找激活系統(tǒng)所用的端口號(hào)將由 ActivationSystem.SYST
EM_PORT 定義。通過(guò)設(shè)置屬性 java.rmi.activation.port 可將該端口覆蓋掉。
如果調(diào)用 setSystem 時(shí)激活系統(tǒng)已經(jīng)設(shè)置好,則該方法將拋出 ActivationExce
ption。
getSystem 方法返回該虛擬機(jī)的激活系統(tǒng)。激活系統(tǒng)可由 setSystem 方法(前述
)設(shè)置。
activeObject 方法是一個(gè)受保護(hù)的方法。子類(lèi)將用它來(lái)對(duì)組監(jiān)控器進(jìn)行 active
Object 回調(diào),以通知監(jiān)控器具有指定激活 id 且其 stub 包含在 mobj 中的遠(yuǎn)程
對(duì)象現(xiàn)在是活動(dòng)的。這一調(diào)用只是轉(zhuǎn)發(fā)給組的 ActivationMonitor。
inactiveGroup 方法是一個(gè)受保護(hù)的方法。子類(lèi)用它來(lái)通知組監(jiān)控器該組已變成
非活動(dòng)的。當(dāng)組中每個(gè)參與虛擬機(jī)中激活活動(dòng)的對(duì)象都變成非活動(dòng)時(shí),子類(lèi)就進(jìn)
行此調(diào)用。
7.4.9 MarshalledObject 類(lèi)
MarshalledObject 是某個(gè)對(duì)象的容器,它允許在進(jìn)行 RMI 調(diào)用時(shí)將該對(duì)象當(dāng)作
一個(gè)參數(shù)來(lái)傳遞,但它延遲該對(duì)象在接收端上的序列化恢復(fù),直到應(yīng)用程序明確
地請(qǐng)求該對(duì)象(通過(guò)調(diào)用該容器對(duì)象)。包含在該 MarshalledObject 中的可序
列化對(duì)象是用相同的語(yǔ)義(該語(yǔ)義作為 RMI 調(diào)用中的參數(shù)來(lái)傳遞)來(lái)序列化和序
列化恢復(fù)的(請(qǐng)求時(shí))。也就是說(shuō),MarshalledObject 中的任一遠(yuǎn)程對(duì)象都可表
示為其 stub 的序列化實(shí)例。MarshalledObject 所包含的對(duì)象可以是遠(yuǎn)程對(duì)象、
非遠(yuǎn)程對(duì)象或遠(yuǎn)程對(duì)象和非遠(yuǎn)程對(duì)象的完整圖形。
當(dāng)對(duì)象被放入 MarshalledObject 的 wrapper 中時(shí),該對(duì)象的序列化形式將被注
釋為 cadebase URL(可從中加載類(lèi));同樣,當(dāng)從對(duì)象的 MarshalledObject
的 wrapper 中取回該對(duì)象時(shí),如果本地沒(méi)有該對(duì)象的代碼,則使用該 URL(序列
化時(shí)所注解的)來(lái)定位和加載該對(duì)象類(lèi)的字節(jié)代碼。
package java.rmi;
public final class MarshalledObject implements java.io.Serializable
{
public MarshalledObject(Object obj) throws java.io.IOException;
public Object get()
throws java.io.IOException, ClassNotFoundException;
public int hashCode();
public boolean equals();
}
MarshalledObject 的構(gòu)造函數(shù)將可序列化的對(duì)象 obj 作為單一參數(shù),并將對(duì)象
的編組表示存放在字節(jié)流中。對(duì)象的編組表示保存了對(duì)象在 RMI 調(diào)用時(shí)所傳遞的
語(yǔ)義:
流中的每個(gè)類(lèi)都被注解為其 cadebase URL,以便在重構(gòu)該對(duì)象(通過(guò)調(diào)用 get
方法)時(shí)可以找到各個(gè)類(lèi)的字節(jié)代碼并進(jìn)行加載;
遠(yuǎn)程對(duì)象由它們的代理服務(wù)器 stub 所代替。
當(dāng)把類(lèi) MarshalledObject 的實(shí)例寫(xiě)到 java.io.ObjectOutputStream 中時(shí),所
含對(duì)象的編組形式(在構(gòu)造中創(chuàng)建)亦被寫(xiě)到流中。因此,只有字節(jié)流才被序列
化。
當(dāng)從 java.io.ObjectInputStream 中讀取 MarshalledObject 時(shí),并不把所包含
的對(duì)象序列化恢復(fù)為一個(gè)具體對(duì)象;該對(duì)象將一直保持其編組表示,直到該已編
組對(duì)象的 get 方法被調(diào)用為止。
get 方法總是要用所含對(duì)象的編組形式來(lái)重新構(gòu)造該對(duì)象。內(nèi)部表示將用解編參
數(shù)(用于 RMI 調(diào)用)所用的語(yǔ)義來(lái)進(jìn)行序列化恢復(fù)。因此,對(duì)象表示的序列化恢
復(fù)將用嵌入對(duì)象序列化流中的 URL 注解來(lái)加載類(lèi)的代碼(如果本地沒(méi)有該代碼)
。
對(duì)象編組表示的 hashCode 與傳遞給構(gòu)造函數(shù)的對(duì)象相同。如果進(jìn)行比較的對(duì)象
的編組表示是等價(jià)的,則 equals 方法將返回 true。該 equals 方法所采用的比
較將忽略類(lèi)的 cadebase 注解,即除了序列化表示中各個(gè)類(lèi)的 cadebase 外,只
要兩個(gè)對(duì)象具有相同的序列化表示,則這兩個(gè)對(duì)象就是等價(jià)的。
凡是有該標(biāo)志的文章,都是該blog博主Caoer(草兒)原創(chuàng),凡是索引、收藏
、轉(zhuǎn)載請(qǐng)注明來(lái)處和原文作者。非常感謝。
主題:
概述
激活協(xié)議
“可激活”遠(yuǎn)程對(duì)象的實(shí)現(xiàn)模型
激活接口
.1 概述
分布式對(duì)象系統(tǒng)被設(shè)計(jì)為支持長(zhǎng)期存在的持久對(duì)象。假設(shè)這些系統(tǒng)將由成千(也
許成萬(wàn))個(gè)這樣的對(duì)象組成,則對(duì)象的實(shí)現(xiàn)在無(wú)限期的時(shí)間段內(nèi)被激活并保持活
動(dòng)狀態(tài)是不合理的。這將占用寶貴的系統(tǒng)資源。另外,客戶(hù)機(jī)需要保存對(duì)對(duì)象的
持久引用的能力,這樣在一個(gè)系統(tǒng)崩潰后可以重新建立對(duì)象之間的通訊,因?yàn)橥?nbsp;
常對(duì)一個(gè)分布對(duì)象的引用只有當(dāng)對(duì)象處于活動(dòng)狀態(tài)時(shí)才有效。
對(duì)象激活是一種用來(lái)提供對(duì)對(duì)象持久引用和管理對(duì)象實(shí)現(xiàn)的執(zhí)行的機(jī)制。在 RMI
中,激活允許對(duì)象根據(jù)需要開(kāi)始執(zhí)行。當(dāng)訪問(wèn)(通過(guò)方法調(diào)用)“可激活”遠(yuǎn)程
對(duì)象時(shí),如果該遠(yuǎn)程對(duì)象當(dāng)前尚未執(zhí)行,則系統(tǒng)將在適當(dāng)?shù)?nbsp;Java 虛擬機(jī)中開(kāi)始
該對(duì)象的執(zhí)行。
7.1.1 術(shù)語(yǔ)
活動(dòng) (active) 對(duì)象是在某些系統(tǒng)的 Java 虛擬機(jī)中被實(shí)例化并被導(dǎo)出的遠(yuǎn)程對(duì)
象。非活動(dòng)對(duì)象在虛擬機(jī)中尚未被實(shí)例化(或?qū)С觯?,但能變成活?dòng)狀態(tài)的遠(yuǎn)程
對(duì)象。激活就是將非活動(dòng)對(duì)象轉(zhuǎn)化為活動(dòng)對(duì)象的過(guò)程。激活要求對(duì)象與一臺(tái)虛擬
機(jī)相關(guān)聯(lián),而這將可能需要將該對(duì)象的類(lèi)加載到虛擬機(jī)中,同時(shí)該對(duì)象也恢復(fù)其
持久狀態(tài)(如果有)。
在 RMI 系統(tǒng)中,我們使用了惰性激活。惰性激活就是將一個(gè)對(duì)象的激活延遲到客
戶(hù)機(jī)第一次使用該對(duì)象時(shí)(即第一次方法調(diào)用時(shí))。
7.1.2 惰性激活
遠(yuǎn)程對(duì)象的惰性激活是用不完善遠(yuǎn)程引用(有時(shí)稱(chēng)為不完善塊)實(shí)現(xiàn)的。對(duì)遠(yuǎn)程
對(duì)象的不完善遠(yuǎn)程引用在第一次調(diào)用對(duì)象的方法時(shí),“完善”為活動(dòng)對(duì)象的引用
。每個(gè)不完善引用均保持一個(gè)持久句柄(激活標(biāo)識(shí)符)和對(duì)目標(biāo)遠(yuǎn)程對(duì)象的瞬態(tài)
遠(yuǎn)程引用。遠(yuǎn)程對(duì)象的激活標(biāo)識(shí)符包含足夠的信息來(lái)使第三方激活該對(duì)象。瞬態(tài)
引用是對(duì)可用來(lái)聯(lián)系執(zhí)行對(duì)象的主動(dòng)遠(yuǎn)程對(duì)象的“活動(dòng)”引用。
在不完善引用中,如果對(duì)遠(yuǎn)程對(duì)象的活引用為空,則不認(rèn)為目標(biāo)對(duì)象是主動(dòng)的。
在方法調(diào)用中,不完善引用(對(duì)該對(duì)象)將加入激活協(xié)議以獲得“活”引用,該
引用是對(duì)新激活的對(duì)象的遠(yuǎn)程引用(例如單路傳送 (unicast) 的遠(yuǎn)程引用)。一
旦不完善引用得到活引用,則不完善引用將把方法調(diào)用傳給底層的遠(yuǎn)程引用,而
該遠(yuǎn)程引用又將方法調(diào)用傳給遠(yuǎn)程對(duì)象。
具體的說(shuō),遠(yuǎn)程對(duì)象的 stub 包含一個(gè)“不完善”遠(yuǎn)程引用類(lèi)型,該類(lèi)型既包括:
遠(yuǎn)程對(duì)象的激活標(biāo)識(shí)符,又包括
“活”引用(可能為空),其中包含遠(yuǎn)程對(duì)象的“活動(dòng)”遠(yuǎn)程引用類(lèi)型(例如,
帶有單路傳送語(yǔ)義的遠(yuǎn)程引用類(lèi)型)。
----------------------------------------------------------------------
----------
注意 - RMI 系統(tǒng)對(duì)遠(yuǎn)程調(diào)用保留“至多一次”語(yǔ)義。換句話說(shuō),對(duì)可激活或單路
傳送遠(yuǎn)程對(duì)象的調(diào)用將至多發(fā)送一次。因此,如果對(duì)遠(yuǎn)程對(duì)象的調(diào)用失?。ㄓ蓲?nbsp;
出的 RemoteException 異常表示),則客戶(hù)機(jī)將得到如下保證:遠(yuǎn)程方法的執(zhí)行
不會(huì)超過(guò)一次,甚至根本就不執(zhí)行。
7.2 激活協(xié)議
在遠(yuǎn)程方法調(diào)用期間,如果目標(biāo)對(duì)象的“活”(live) 引用是未知的,則不完善引
用將褂眉せ钚欏<せ钚榘ㄏ鋁屑父鍪堤澹翰煌晟埔謾⒓せ釔鰲ava 虛
擬機(jī)中的激活組和被激活的遠(yuǎn)程對(duì)象。
激活器(通常每個(gè)主機(jī)有一個(gè))是一個(gè)實(shí)體,負(fù)責(zé)激活,它是:
將激活標(biāo)識(shí)符映射到激活對(duì)象所需信息(對(duì)象的類(lèi)、位置 -- URL 路徑 -- 從該
處可加載類(lèi)、對(duì)象可能需要用于自舉 (bootstrap) 的特定數(shù)據(jù)等)的信息數(shù)據(jù)庫(kù),及
Java 虛擬機(jī)的管理器,它啟動(dòng)虛擬機(jī)(必要時(shí))并將對(duì)象激活請(qǐng)求(和必要的信
息一起)傳送到遠(yuǎn)程虛擬機(jī)中正確的激活組。
注意:激活器始終將激活標(biāo)識(shí)符到活動(dòng)對(duì)象的當(dāng)前映射保存在緩存中,這樣就無(wú)
需為每個(gè)激活請(qǐng)求而查詢(xún)?cè)摻M。
激活組(每個(gè) Java 虛擬機(jī)中一個(gè))是這樣的實(shí)體,它接收對(duì)激活 Java 虛擬機(jī)
中對(duì)象的請(qǐng)求并將激活的對(duì)象返給激活器。
激活協(xié)議如下所示。不完善引用使用一個(gè)激活標(biāo)識(shí)符并調(diào)用激活器(內(nèi)部 RMI 接
口)來(lái)激活與該標(biāo)識(shí)符關(guān)聯(lián)的對(duì)象。激活器查找對(duì)象的激活描述符(先前已注冊(cè)
)。對(duì)象的描述符包括:
對(duì)象的組標(biāo)識(shí)符(指定對(duì)象激活時(shí)所處的虛擬機(jī)),
對(duì)象的類(lèi)名,
URL 路徑,從該處加載對(duì)象的類(lèi)代碼,
特定于對(duì)象的已編組的初始化數(shù)據(jù)(例如,初始化數(shù)據(jù)可能是包含對(duì)象持久狀態(tài)
的文件的名稱(chēng))。
如果應(yīng)容納該對(duì)象的激活組存在,則激活器將激活請(qǐng)求傳送到該組。如果激活組
不存在,則激活器將啟動(dòng)虛擬機(jī)以執(zhí)行激活組,然后將激活請(qǐng)求傳送到該組。
激活組將加載對(duì)象的類(lèi)并用特定的構(gòu)造函數(shù)來(lái)實(shí)例化該對(duì)象。此構(gòu)造函數(shù)帶多個(gè)
參數(shù),包括先前注冊(cè)的激活描述符。
對(duì)象完成激活時(shí),激活組將把已編組對(duì)象引用傳回激活器,然后該激活器記錄激
活標(biāo)識(shí)符和激活引用對(duì),并將活動(dòng)(活)引用返給不完善引用。隨后,不完善引
用(在 stub 內(nèi))通過(guò)活動(dòng)引用將方法調(diào)用直接傳給遠(yuǎn)程對(duì)象。
----------------------------------------------------------------------
----------
注意 - 在 JDK 中,RMI 提供激活系統(tǒng)接口的實(shí)現(xiàn)。要使用激活,必須首先運(yùn)行
激活系統(tǒng)守護(hù)進(jìn)程 (daemon) rmid。
7.3 “可激活”遠(yuǎn)程對(duì)象的實(shí)現(xiàn)模型
為了使可通過(guò)激活標(biāo)識(shí)符訪問(wèn)的遠(yuǎn)程對(duì)象不受時(shí)間影響,開(kāi)發(fā)人員必須做到:
為該遠(yuǎn)程對(duì)象注冊(cè)一個(gè)激活描述符
在對(duì)象的類(lèi)中包含一個(gè)專(zhuān)用構(gòu)造函數(shù),當(dāng) RMI 系統(tǒng)激活可激活對(duì)象時(shí)將調(diào)用它。
可用以下幾種方法來(lái)注冊(cè)激活描述符 (ActivationDesc):
調(diào)用類(lèi) Activatable 的靜態(tài) register 方法
用 Activatable 類(lèi)的第一個(gè)或第二個(gè)構(gòu)造函數(shù)創(chuàng)建“可激活”對(duì)象
顯式地導(dǎo)出“可激活”對(duì)象。該過(guò)程可用 Activatable 的第一個(gè)或第二個(gè) expo
rtObject 方法實(shí)現(xiàn),其參數(shù)為 ActivationDesc、Remote 對(duì)象的實(shí)現(xiàn)和端口號(hào)。
對(duì)于特定對(duì)象,只可用上述三種方法之一來(lái)注冊(cè)激活對(duì)象。有關(guān)如何實(shí)現(xiàn)可激活
對(duì)象的示例,請(qǐng)參閱后面的“構(gòu)造可激活遠(yuǎn)程對(duì)象”。
7.3.1 ActivationDesc 類(lèi)
ActivationDesc 含有激活對(duì)象所需的信息。它包含對(duì)象的激活組標(biāo)識(shí)符、對(duì)象的
類(lèi)名、加載對(duì)象代碼的 codebase 路徑(或 URL)及 MarshalledObject(可包含
每次激活期間所用的對(duì)象特定初始化數(shù)據(jù))。
激活過(guò)程中將查詢(xún)?cè)诩せ钕到y(tǒng)中注冊(cè)的描述符以獲取有關(guān)的信息,從而用于重新
創(chuàng)建或激活對(duì)象。對(duì)象的描述符中的 MarshalledObject 將作為第二個(gè)參數(shù)傳給
遠(yuǎn)程對(duì)象的構(gòu)造函數(shù),以供激活過(guò)程使用。
package java.rmi.activation;
public final class ActivationDesc implements java.io.Serializable
{
public ActivationDesc(String className, String codebase,
java.rmi.MarshalledObject data)
throws ActivationException;
public ActivationDesc(String className, String codebase,
java.rmi.MarshalledObject data,
boolean restart)
throws ActivationException;
public ActivationDesc(ActivationGroupID groupID,
String className,
String codebase,
java.rmi.MarshalledObject data,
boolean restart);
public ActivationDesc(ActivationGroupID groupID,
String className,
String codebase,
java.rmi.MarshalledObject data);
public ActivationGroupID getGroupID();
public String getClassName();
public String getLocation();
public java.rmi.MarshalledObject getData()
public boolean getRestartMode();
}
ActivationDesc 的第一個(gè)構(gòu)造函數(shù)構(gòu)造一個(gè)對(duì)象的對(duì)象描述符,這個(gè)對(duì)象的類(lèi)是
className(可從 codebase 路徑加載),它的初始化信息(已編組形式)為 d
ata。如果使用這種形式的構(gòu)造函數(shù),則對(duì)象的組標(biāo)識(shí)符缺省為該虛擬機(jī) Activa
tionGroup 的當(dāng)前標(biāo)識(shí)符。具有相同 ActivationGroupID 的所有對(duì)象都將在同一
虛擬機(jī)中被激活。如果當(dāng)前組是非活動(dòng)的或無(wú)法創(chuàng)建缺省組,則將拋出 Activat
ionException。如果 groupID 為 null,則將拋出 IllegalArgumentException。
----------------------------------------------------------------------
----------
注意 - 作為創(chuàng)建 ActivationDesc 的副效應(yīng),如果該虛擬機(jī)的 ActivationGrou
p 當(dāng)前不是活動(dòng)的,則將創(chuàng)建缺省 ActivationGroup。缺省激活組將 java.rmi.
RMISecurityManager 作為安全管理器,并在重新激活時(shí)將激活組虛擬機(jī)中的屬性
設(shè)置為該虛擬機(jī)中的當(dāng)前屬性。如果應(yīng)用程序需用不同的安全管理器,則在創(chuàng)建
缺省 ActivationDesc 之前必須設(shè)置該虛擬機(jī)的組。有關(guān)如何為虛擬機(jī)創(chuàng)建 Act
ivationGroup 的詳細(xì)信息,參見(jiàn)方法 ActivationGroup.createGroup。
----------------------------------------------------------------------
----------
ActivationDesc 第二個(gè)構(gòu)造函數(shù)構(gòu)造對(duì)象描述符的方式與第一個(gè)構(gòu)造函數(shù)相同,
但必須提供附加的參數(shù) restart。如果對(duì)象要求重啟服務(wù),這意味著當(dāng)激活器重
新啟動(dòng)時(shí),對(duì)象也會(huì)自動(dòng)重新啟動(dòng)(與根據(jù)需要激活的惰性激活相反)。此時(shí),
restart 應(yīng)為 true。如果 restart 為 false,則對(duì)象將只是在需要時(shí)激活(通
過(guò)遠(yuǎn)程方法調(diào)用)。
ActivationDesc 的第三個(gè)構(gòu)造函數(shù)構(gòu)造一個(gè)對(duì)象的對(duì)象描述符。這個(gè)對(duì)象的組標(biāo)
識(shí)符為 groupID,它的類(lèi)名為 className(可從 codebase 路徑加載),它的初
始化信息為 data。所有具有相同 groupID 的對(duì)象都將在同一 Java 虛擬機(jī)中被
激活。
ActivationDesc 第四個(gè)構(gòu)造函數(shù)構(gòu)造對(duì)象描述符的方式與第三個(gè)構(gòu)造函數(shù)相同,
但它允許指定重啟模式。如果對(duì)象需要重新啟動(dòng)(定義如上),則 restart 應(yīng)為
true。
getGroupID 方法返回該描述符所指定對(duì)象的組標(biāo)識(shí)符。組可以提供一種將對(duì)象聚
合到單一 Java 虛擬機(jī)中的方法。
getClassName 方法返回該激活描述符所指定對(duì)象的類(lèi)名。
getLocation 方法返回用于下載該對(duì)象的類(lèi)的 codebase 路徑。
getData 方法返回一個(gè)“已編組對(duì)象”,該編組對(duì)象包含用于初始化(激活)描
述符指定的對(duì)象的數(shù)據(jù)。
getRestartMode 方法在該對(duì)象的重啟模式啟用時(shí)返回 true,否則返回 false。
7.3.2 ActivationID 類(lèi)
激活協(xié)議利用激活標(biāo)識(shí)符來(lái)表示不受時(shí)間影響的可激活遠(yuǎn)程對(duì)象。激活標(biāo)識(shí)符(
類(lèi) ActivationID 的實(shí)例)含有激活對(duì)象所需的若干信息:
對(duì)象激活器的遠(yuǎn)程引用
對(duì)象的唯一標(biāo)識(shí)符。
對(duì)象的激活標(biāo)識(shí)符可通過(guò)向激活系統(tǒng)注冊(cè)對(duì)象來(lái)得到??捎孟率鰩追N方法之一來(lái)
完成注冊(cè)(如上所述):
通過(guò) Activatable.register 方法
通過(guò)第一個(gè)或第二個(gè) Activatable 構(gòu)造函數(shù)(都有三個(gè)參數(shù)而且注冊(cè)并導(dǎo)出對(duì)象
)
通過(guò)第一個(gè)或第二個(gè) Activatable.exportObject 方法(它們以激活描述符、對(duì)
象實(shí)現(xiàn)及端口為參數(shù),且都注冊(cè)并導(dǎo)出對(duì)象)。
package java.rmi.activation;
public class ActivationID implements java.io.Serializable
{
public ActivationID(Activator activator);
public Remote activate(boolean force)
throws ActivationException, UnknownObjectException, java.rmi.RemoteException;
public boolean equals(Object obj);
public int hashCode();
}
ActivationID 的構(gòu)造函數(shù)接受參數(shù) activator,該參數(shù)指定對(duì)激活器(負(fù)責(zé)激活
與該激活標(biāo)識(shí)符關(guān)聯(lián)的對(duì)象)的遠(yuǎn)程引用。ActivationID 的實(shí)例是全局唯一的。
activate 方法將激活與該激活標(biāo)識(shí)符關(guān)聯(lián)的對(duì)象。如果 force 參數(shù)為 true,激
活器將把遠(yuǎn)程對(duì)象的任何高速緩存引用視為已過(guò)時(shí),從而迫使激活器在激活對(duì)象
時(shí)與組聯(lián)系。如果 force 為 false,則返回可接受的高速緩存值。如果激活失敗
,則拋出 ActivationException。如果激活器不能識(shí)別該對(duì)象標(biāo)識(shí)符,則該方法
將拋出 UnknownObjectException。如果對(duì)激活器的遠(yuǎn)程調(diào)用失敗,則拋出
RemoteException。
equals 方法可實(shí)現(xiàn)基于內(nèi)容的相等比較。如果所有的域都相等(完全相同或從各
域的 Object.equals 語(yǔ)義上等價(jià)),它將返回 true。如果 p1 和 p2 是類(lèi) Act
ivationID 的實(shí)例,則在 p1.equals(p2) 返回 true 時(shí) hashCode 方法返回相同
的值。
7.3.3 Activatable 類(lèi)
Activatable 類(lèi)提供對(duì)需要持久訪問(wèn)而不受時(shí)間影響,同時(shí)又被系統(tǒng)激活的遠(yuǎn)程
對(duì)象的支持。類(lèi) Activatable 是開(kāi)發(fā)人員用來(lái)實(shí)現(xiàn)和管理可激活對(duì)象的主要應(yīng)用
程序接口。注意,必須先運(yùn)行激活系統(tǒng)守護(hù)進(jìn)程 rmid,然后才能注冊(cè)和/或激活
對(duì)象。
package java.rmi.activation;
public abstract class Activatable
extends java.rmi.server.RemoteServer
{
protected Activatable(String codebase,
java.rmi.MarshalledObject data,
boolean restart,
int port)
throws ActivationException, java.rmi.RemoteException;
protected Activatable(String codebase,
java.rmi.MarshalledObject data,
boolean restart,
int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
throws ActivationException, java.rmi.RemoteException;
protected Activatable(ActivationID id, int port)
throws java.rmi.RemoteException;
protected Activatable(ActivationID id, int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
throws java.rmi.RemoteException;
protected ActivationID getID();
public static Remote register(ActivationDesc desc)
throws UnknownGroupException, ActivationException,
java.rmi.RemoteException;
public static boolean inactive(ActivationID id)
throws UnknownObjectException, ActivationException,
java.rmi.RemoteException;
public static void unregister(ActivationID id)
throws UnknownObjectException, ActivationException,
java.rmi.RemoteException;
public static ActivationID exportObject(Remote obj,
String codebase,
MarshalledObject data,
boolean restart,
int port)
throws ActivationException, java.rmi.RemoteException;
public static ActivationID exportObject(Remote obj,
String codebase,
MarshalledObject data,
boolean restart,
int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
throws ActivationException, java.rmi.RemoteException;
public static Remote exportObject(Remote obj,
ActivationID id,
int port)
throws java.rmi.RemoteException;
public static Remote exportObject(Remote obj,
ActivationID id,
int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
throws java.rmi.RemoteException;
public static boolean unexportObject(Remote obj, boolean force)
throws java.rmi.NoSuchObjectException;
}
可激活遠(yuǎn)程對(duì)象的實(shí)現(xiàn)可能擴(kuò)展或不擴(kuò)展類(lèi) Activatable。確實(shí)擴(kuò)展 Activatab
le 類(lèi)的遠(yuǎn)程對(duì)象實(shí)現(xiàn)將從超類(lèi) java.rmi.server.RemoteObject 中繼承 hashCo
de 和 equals 方法中的相應(yīng)定義。因此,引用同一 Activatable 遠(yuǎn)程對(duì)象的兩
個(gè)遠(yuǎn)程引用是相等的(equals 方法將返回 true)。同樣,類(lèi) Activatable 的實(shí)
例將“等于”該實(shí)例的相應(yīng) stub 對(duì)象(即如果 Object.equals 方法用與該實(shí)現(xiàn)
匹配的 stub 對(duì)象作為參數(shù)進(jìn)行調(diào)用,它將返回 true。反之亦然)。
Activatable 類(lèi)方法
Activatable 類(lèi)的第一個(gè)構(gòu)造函數(shù)用于在指定 port 上注冊(cè)和導(dǎo)出對(duì)象(如果 p
ort 為零,則選用某個(gè)匿名端口)。下載的類(lèi)代碼對(duì)象的 URL 路徑是 codbase,
其初始化數(shù)據(jù)是 data。如果 restart 為 true,則對(duì)象將在激活器重新啟動(dòng)或組
失效時(shí)自動(dòng)重新啟動(dòng)。如果 restart 為 false,則對(duì)象將根據(jù)需要而激活(通過(guò)
對(duì)對(duì)象的遠(yuǎn)程方法調(diào)用)。
Activatable 類(lèi)的具體子類(lèi)必須調(diào)用該構(gòu)造函數(shù)才能在初始構(gòu)造期間注冊(cè)和導(dǎo)出
該對(duì)象。作為構(gòu)造可激活對(duì)象時(shí)的副效應(yīng),遠(yuǎn)程對(duì)象將被“注冊(cè)”到激活系統(tǒng)上
并“導(dǎo)出”(如果 port 為零,則在匿名端口導(dǎo)出)到 RMI 運(yùn)行時(shí),從而使之可
接受來(lái)自客戶(hù)機(jī)的到來(lái)調(diào)用。
如果向激活系統(tǒng)注冊(cè)對(duì)象失敗,則該構(gòu)造函數(shù)將拋出 ActivationException。如
果將對(duì)象導(dǎo)出到 RMI 運(yùn)行時(shí)失敗,則將拋出 RemoteException。
第二個(gè)構(gòu)造函數(shù)與第一個(gè) Activatable 構(gòu)造函數(shù)相同,但它允許將客戶(hù)機(jī)和服務(wù)
器套接字工廠規(guī)范用于與該可激活對(duì)象進(jìn)行通訊。詳細(xì)信息,參見(jiàn)“RMI 套接字
工廠”。
第三個(gè)構(gòu)造函數(shù)用于激活對(duì)象并從指定的 port 將其(用 ActivationID,id)導(dǎo)
出。當(dāng)對(duì)象本身被其專(zhuān)用的“激活”構(gòu)造函數(shù)激活時(shí),Activatable 類(lèi)的具體子
類(lèi)必須調(diào)用該構(gòu)造函數(shù)。該“激活”構(gòu)造函數(shù)的參數(shù)必須是:
對(duì)象的激活標(biāo)識(shí)符 (ActivationID) 及
對(duì)象的初始化/自舉數(shù)據(jù) (MarshalledObject)。
作為構(gòu)造的副效應(yīng),遠(yuǎn)程對(duì)象將被“導(dǎo)出”到 RMI 運(yùn)行時(shí)中(從指定 port)并
可接受來(lái)自客戶(hù)機(jī)的調(diào)用。如果將對(duì)象導(dǎo)出到 RMI 運(yùn)行時(shí)失敗,則該構(gòu)造函數(shù)將
拋出 RemoteException。
第四個(gè)構(gòu)造函數(shù)與第三個(gè)構(gòu)造函數(shù)相同,但它允許將客戶(hù)機(jī)和服務(wù)器套接字工廠
規(guī)范用于與該可激活對(duì)象進(jìn)行通訊。
getID 方法返回對(duì)象的激活標(biāo)識(shí)符。該方法是受保護(hù)的,因而只有子類(lèi)才能獲取
對(duì)象的標(biāo)識(shí)符。 對(duì)象的標(biāo)識(shí)符用于報(bào)告對(duì)象的非活動(dòng)狀態(tài)或注銷(xiāo)對(duì)象的激活描述
符。
register 方法為可激活的遠(yuǎn)程對(duì)象向激活系統(tǒng)注冊(cè)對(duì)象描述符 desc,從而使該
對(duì)象能在需要時(shí)被激活。該方法可用于注冊(cè)可激活對(duì)象而無(wú)需先創(chuàng)建該對(duì)象。它
返回可激活對(duì)象的 Remote stub,因此可加以保存并在今后調(diào)用,從而強(qiáng)制首次
創(chuàng)建/激活該對(duì)象。如果沒(méi)有向激活系統(tǒng)注冊(cè) desc 中的組標(biāo)識(shí)符,該方法將拋出
UnknownGroupException。如果激活系統(tǒng)未運(yùn)行,則拋出 ActivationException
。最后,如果對(duì)激活系統(tǒng)的遠(yuǎn)程調(diào)用失敗,則拋出 RemoteException。
inactive 方法用于通知系統(tǒng)具有相應(yīng)激活 id 的對(duì)象當(dāng)前是非活動(dòng)的。如果已知
該對(duì)象當(dāng)前是活動(dòng)的,則該對(duì)象將不從 RMI 運(yùn)行時(shí)環(huán)境中導(dǎo)出(僅在沒(méi)有待定的
或執(zhí)行的調(diào)用時(shí)),從而可不再接收到來(lái)的調(diào)用。該調(diào)用還將通知該虛擬機(jī)的 A
ctivationGroup 該對(duì)象處于非活動(dòng)狀態(tài);而該組又將通知其 ActivationMonito
r。如果該調(diào)用成功,則此后對(duì)激活器的激活請(qǐng)求將導(dǎo)致重新激活該對(duì)象。如果成
功地阻止該對(duì)象被導(dǎo)出(意味著此時(shí)它沒(méi)有待定或執(zhí)行調(diào)用),則 inactive 方
法返回 true;如果由于待定或進(jìn)程內(nèi)調(diào)用而不能阻止該對(duì)象被導(dǎo)出,則返回 fa
lse。如果對(duì)象是未知的(它可能是非活動(dòng)的),則該方法將拋出 UnknownObjec
tException;如果組是非活動(dòng)的,則拋出 ActivationException;如果通知顯示
器的調(diào)用失敗,則拋出 RemoteException。如果該對(duì)象被認(rèn)為是活動(dòng)的但已自己
阻止導(dǎo)出,則該操作仍將成功進(jìn)行。
unregister 方法用于撤消與 id 關(guān)聯(lián)的激活描述符的先前注冊(cè)。對(duì)象不能再用這
個(gè) id 來(lái)激活。如果該對(duì)象 id 對(duì)激活系統(tǒng)來(lái)說(shuō)是未知的,則拋出 UnknownObje
ctException。如果激活系統(tǒng)未處于運(yùn)行狀態(tài),則拋出 ActivationException。如
果對(duì)激活系統(tǒng)的遠(yuǎn)程調(diào)用失敗,則拋出 RemoteException。
第一個(gè) exportObject 方法可被“可激活”但不擴(kuò)展 Activatable 類(lèi)的對(duì)象顯式
調(diào)用,其目的是:a) 向激活系統(tǒng)注冊(cè)對(duì)象的激活描述符 desc,由所提供的 cod
ebase 和 data 構(gòu)造(因此可激活該對(duì)象);b) 從指定 port 導(dǎo)出遠(yuǎn)程對(duì)象 ob
j(如果該 port 為零,則將選擇匿名端口)。對(duì)象一旦被導(dǎo)出,即可接收到來(lái)的
調(diào)用。
該 exportObject 方法返回向激活系統(tǒng)注冊(cè)描述符 desc 時(shí)所獲得的激活標(biāo)識(shí)符
。如果在虛擬機(jī)中激活組不是活動(dòng)的,則拋出 ActivationException。如果對(duì)象
注冊(cè)或?qū)С鍪?,則拋出 RemoteException。
如果 obj 擴(kuò)展 Activatable,則不必調(diào)用該方法,因?yàn)榈谝粋€(gè) Activatable 構(gòu)
造函數(shù)將調(diào)用該方法。
第二個(gè) exportObject 方法與第一個(gè)相同,但它允許將客戶(hù)機(jī)和服務(wù)器套接字工
廠規(guī)范用于與該可激活對(duì)象進(jìn)行通訊。
第三個(gè) exportObject 方法將帶標(biāo)識(shí)符 id 的“可激活”遠(yuǎn)程對(duì)象(不一定是 A
ctivatable 類(lèi)型的)導(dǎo)出到 RMI 運(yùn)行時(shí),以使對(duì)象 obj 能夠接收到來(lái)的調(diào)用。
如果 port 為零,則將在某個(gè)匿名端口導(dǎo)出該對(duì)象。
激活時(shí),不擴(kuò)展 Activatable 類(lèi)的“可激活”對(duì)象應(yīng)顯式地調(diào)用此 exportObje
ct 方法。確實(shí)擴(kuò)展 Activatable 類(lèi)的對(duì)象不必直接調(diào)用該方法;它將被上面的
第三個(gè)構(gòu)造函數(shù)所調(diào)用(應(yīng)從其專(zhuān)用的激活構(gòu)造函數(shù)中調(diào)用子類(lèi))。
該 exportObject 方法將返回可激活對(duì)象的 Remote stub。如果該對(duì)象的導(dǎo)出失
敗,則該方法將拋出 RemoteException。
第四個(gè) exportObject 方法與第三個(gè)相同,但它允許將客戶(hù)機(jī)和服務(wù)器套接字工
廠規(guī)范用于與該可激活對(duì)象進(jìn)行通訊。
unexportObject 方法使遠(yuǎn)程對(duì)象 obj 不能接收到來(lái)的調(diào)用。如果參數(shù) force 為
true,則即使有對(duì)遠(yuǎn)程對(duì)象的待定調(diào)用或遠(yuǎn)程對(duì)象在進(jìn)程內(nèi)仍有調(diào)用,對(duì)象也將
被強(qiáng)制阻止導(dǎo)出。如果參數(shù) force 為 false,則只在沒(méi)有對(duì)對(duì)象的待定調(diào)用或進(jìn)
程內(nèi)沒(méi)有調(diào)用時(shí)它才被阻止導(dǎo)出。如果成功地阻止了該對(duì)象的導(dǎo)出,則 RMI 運(yùn)行
時(shí)將從其內(nèi)部表中刪掉它。使用這種強(qiáng)制方式從 RMI 刪除對(duì)象可能會(huì)使客戶(hù)機(jī)持
有遠(yuǎn)程對(duì)象的過(guò)時(shí)遠(yuǎn)程引用。如果此前沒(méi)有將對(duì)象導(dǎo)出到 RMI 運(yùn)行時(shí),則該方法
將拋出 java.rmi.NoSuchObjectException。
構(gòu)造可激活的遠(yuǎn)程對(duì)象
為了使對(duì)象可激活,“可激活”對(duì)象實(shí)現(xiàn)類(lèi)不管是否擴(kuò)展 Activatable 類(lèi),都必
須定義一個(gè)特殊的公共構(gòu)造函數(shù)。該公共構(gòu)造函數(shù)帶有兩個(gè)參數(shù):激活標(biāo)識(shí)符(
類(lèi)型為 ActivationID)及激活數(shù)據(jù) java.rmi.MarshalledObject(在注冊(cè)時(shí)所用
的激活描述符中提供)。當(dāng)激活組在其虛擬機(jī)內(nèi)激活某個(gè)遠(yuǎn)程對(duì)象時(shí),它將利用
此特殊構(gòu)造函數(shù)來(lái)構(gòu)造對(duì)象(后面將作詳細(xì)說(shuō)明)。遠(yuǎn)程對(duì)象實(shí)現(xiàn)可適當(dāng)用激活
數(shù)據(jù)來(lái)初始化自己。遠(yuǎn)程對(duì)象也可能想保留其激活標(biāo)識(shí)符,這樣就可以在它變?yōu)?nbsp;
非活動(dòng)狀態(tài)(通過(guò)對(duì) Activatable. inactive 方法的調(diào)用)時(shí)通知激活組。
Activatable 構(gòu)造函數(shù)的第一種和第二種形式用于從指定的 port 注冊(cè)并導(dǎo)出可
激活對(duì)象。最初構(gòu)造對(duì)象時(shí)應(yīng)使用該構(gòu)造函數(shù);該構(gòu)造函數(shù)的第三種形式將在重
新激活對(duì)象時(shí)使用。
Activatable 的具體子類(lèi)必須在最初構(gòu)造期間調(diào)用第一種或第二種構(gòu)造函數(shù)以注
冊(cè)并導(dǎo)出對(duì)象。 構(gòu)造函數(shù)首先用對(duì)象的類(lèi)名創(chuàng)建一個(gè)激活描述符 (ActivationD
esc)、對(duì)象所提供的 codebase 和 data(其激活組為虛擬機(jī)的缺省激活組)。然
后,構(gòu)造函數(shù)將向缺省的 ActivationSystem 注冊(cè)該描述符。最后,構(gòu)造函數(shù)在
特定 port 上(如果 port 為零,則選擇匿名端口)將可激活對(duì)象導(dǎo)出到 RMI 運(yùn)
行時(shí)中,并將該對(duì)象作為 activeObject 報(bào)告給本地 ActivationGroup。如果在
注冊(cè)或?qū)С龅倪^(guò)程中出錯(cuò),則構(gòu)造函數(shù)拋出 RemoteException。注意,構(gòu)造函數(shù)
也初始化它的 ActivationID(通過(guò)注冊(cè)獲得),因此接下來(lái)對(duì) protected 方法
getID 的調(diào)用將返回對(duì)象的激活標(biāo)識(shí)符。
Activatable 構(gòu)造函數(shù)的第三種形式用于從指定的端口導(dǎo)出對(duì)象。當(dāng) Activatab
le 的具體子類(lèi)被對(duì)象自己的“激活”構(gòu)造函數(shù)激活時(shí),必須調(diào)用第三種構(gòu)造函數(shù)
。該“激活”構(gòu)造函數(shù)帶兩個(gè)參數(shù):
對(duì)象的 ActivationID
對(duì)象的初始化數(shù)據(jù),一個(gè) MarshalledObject 對(duì)象
該構(gòu)造函數(shù)只將可激活對(duì)象從特定 port(如果 port 為零,則選擇匿名端口)導(dǎo)
出到 RMI 運(yùn)行時(shí)中,而并不通知 ActivationGroup 該對(duì)象已是活動(dòng)對(duì)象。因?yàn)?nbsp;
正是 ActivationGroup 激活該對(duì)象的,因而它自然知道對(duì)象已處活動(dòng)狀態(tài)。
下面是遠(yuǎn)程對(duì)象接口 Server 和擴(kuò)展 Activatable 類(lèi)的實(shí)現(xiàn) ServerImpl 的示例:
package examples;
public interface Server extends java.rmi.Remote
{
public void doImportantStuff()
throws java.rmi.RemoteException;
}
public class ServerImpl extends Activatable implements Server
{
// 初始構(gòu)造、注冊(cè)及導(dǎo)出時(shí)的構(gòu)造函數(shù)
public ServerImpl(String codebase, MarshalledObject data)
throws ActivationException, java.rmi.RemoteException
{
// 向激活系統(tǒng)注冊(cè)對(duì)象,然后
// 在匿名端口上導(dǎo)出
super(codebase, data, false, 0);
}
// 激活及導(dǎo)出的構(gòu)造函數(shù)。該構(gòu)造函數(shù)由
// ActivationInstantiator.newInstance
// 方法在激活過(guò)程中所調(diào)用,以構(gòu)造對(duì)象
public ServerImpl(ActivationID id, MarshalledObject data)
throws java.rmi.RemoteException
{
// 調(diào)用父類(lèi)的構(gòu)造函數(shù)以
// 將對(duì)象導(dǎo)出到 RMI 運(yùn)行時(shí)。
super(id, 0);
// 初始化對(duì)象(例如利用數(shù)據(jù))
}
public void doImportantStuff() { ... }
}
對(duì)象將負(fù)責(zé)導(dǎo)出自己。Activatable 的構(gòu)造函數(shù)負(fù)責(zé)將對(duì)象導(dǎo)出到具有活動(dòng)引用
類(lèi)型 UnicastRemoteObject 的 RMI 運(yùn)行時(shí)中,因此,擴(kuò)展 Activatable 的對(duì)象
實(shí)現(xiàn)不必關(guān)心顯式導(dǎo)出對(duì)象(不是調(diào)用相應(yīng)的超類(lèi)構(gòu)造函數(shù))的具體細(xì)節(jié)。如果
對(duì)象實(shí)現(xiàn)不擴(kuò)展類(lèi) Activatable,則該對(duì)象必須通過(guò)調(diào)用某個(gè) Activatable.exp
ortObject 靜態(tài)方法來(lái)顯式導(dǎo)出該對(duì)象。
下例中,ServerImpl 不擴(kuò)展 Activatable,而是擴(kuò)展另一個(gè)類(lèi)。因此,ServerI
mpl 負(fù)責(zé)在初始構(gòu)造和激活過(guò)程中導(dǎo)出自己。下述的類(lèi)定義給出了 ServerImpl
的初始化構(gòu)造函數(shù)及其特殊“激活”構(gòu)造函數(shù),以及每個(gè)構(gòu)造函數(shù)內(nèi)用于導(dǎo)出對(duì)
象的相應(yīng)調(diào)用:
package examples;
public class ServerImpl extends SomeClass implements Server
{
// 初始創(chuàng)建時(shí)的構(gòu)造函數(shù)
public ServerImpl(String codebase, MarshalledObject data)
throws ActivationException, java.rmi.RemoteException
{
// 注冊(cè)并導(dǎo)出對(duì)象
Activatable.exportObject(this, codebase, data, false, 0);
}
// 激活的構(gòu)造函數(shù)
public ServerImpl(ActivationID id, MarshalledObject data)
throws java.rmi.RemoteException
{
// 導(dǎo)出對(duì)象
Activatable.exportObject(this, id, 0);
}
public void doImportantStuff() { ... }
}
在不創(chuàng)建對(duì)象的情況下注冊(cè)激活描述符
要在不創(chuàng)建對(duì)象的情況下向激活系統(tǒng)注冊(cè)可激活遠(yuǎn)程對(duì)象,程序員只需為對(duì)象注
冊(cè)激活描述符(類(lèi) ActivationDesc 的實(shí)例)。激活描述符含有一切所需的信息
,因此必要時(shí)激活系統(tǒng)就可以激活該對(duì)象。可用以下方法來(lái)注冊(cè)類(lèi) examples.Se
rverImpl 實(shí)例的激活描述符(忽略異常處理):
Server server;ActivationDesc desc;String codebase = "http://zaphod/cod
ebase/";
MarshalledObject data = new MarshalledObject("some data");desc = new A
ctivationDesc( "examples.ServerImpl", codebase, data);server = (Server
)Activatable.register(desc);
register 調(diào)用將返回一個(gè) Remote stub(它是 examples.ServerImpl 對(duì)象的 s
tub),并實(shí)現(xiàn)一組與 examples.ServerImpl 所實(shí)現(xiàn)的遠(yuǎn)程接口相同的遠(yuǎn)程接口
(即 stub 實(shí)現(xiàn)遠(yuǎn)程接口 Server)。該 stub 對(duì)象(上述被強(qiáng)制類(lèi)型轉(zhuǎn)換并指派
給 server 的對(duì)象)可作為參數(shù)傳給期望實(shí)現(xiàn) examples.Server 遠(yuǎn)程接口的對(duì)象
的任何方法調(diào)用。
7.4 激活接口
在 RMI 激活協(xié)議中,為使系統(tǒng)運(yùn)轉(zhuǎn)正常,激活器必須保證以下兩點(diǎn):
象所有的系統(tǒng)守護(hù)進(jìn)程一樣,計(jì)算機(jī)處于打開(kāi)狀態(tài)時(shí)激活器必須保持運(yùn)行狀態(tài)
激活器不能重新激活已處在活動(dòng)狀態(tài)的遠(yuǎn)程對(duì)象。
激活器將為它所要激活的組和對(duì)象維護(hù)一個(gè)相應(yīng)的信息數(shù)據(jù)庫(kù)。
7.4.1 激活器接口
激活器是參與激活進(jìn)程的實(shí)體之一。如前所述,stub 內(nèi)的不完善引用將通過(guò)調(diào)用
激活器的 activate 方法來(lái)獲得對(duì)可激活遠(yuǎn)程對(duì)象的“活”引用。激活器接到激
活請(qǐng)求后,就開(kāi)始查找該激活標(biāo)識(shí)符 id 的激活描述符,以決定要在哪個(gè)組中激
活對(duì)象,然后調(diào)用激活組的實(shí)例化器的newInstance 方法(ActivationGroup 的
遠(yuǎn)程接口將在后面說(shuō)明)。激活器將根據(jù)需要啟動(dòng)激活組的執(zhí)行過(guò)程。例如,如
果給定的組描述符的激活組還未運(yùn)行,則激活器將為該激活組生成一個(gè)子虛擬機(jī)
,以便在該新虛擬機(jī)中建立該組。
激活器將負(fù)責(zé)監(jiān)控和檢測(cè)激活組何時(shí)失敗,以便將過(guò)時(shí)的遠(yuǎn)程引用從其內(nèi)部表中
刪去。
package java.rmi.activation;
public interface Activator extends java.rmi.Remote
{
java.rmi.MarshalledObject activate(ActivationID id, boolean force)
throws UnknownObjectException, ActivationException,
java.rmi.RemoteException;
}
activate 方法激活與激活標(biāo)識(shí)符 id 所關(guān)聯(lián)的對(duì)象。如果激活器知道對(duì)象已經(jīng)為
活動(dòng)對(duì)象,且 force 參數(shù)為 false,就會(huì)立即將含有“活”引用的 stub 返給調(diào)
用程序;如果激活器不知道相應(yīng)的遠(yuǎn)程對(duì)象是活動(dòng)的或 force 參數(shù)為 true,則
激活器將利用激活描述符信息(先前已為獲得 id 而注冊(cè)過(guò))來(lái)決定對(duì)象應(yīng)該在
哪個(gè)組(虛擬機(jī))中被激活。如果對(duì)象組的相應(yīng)激活 Instantiator 已經(jīng)存在,
則激活器將通過(guò)傳遞 id 和對(duì)象的激活描述符來(lái)調(diào)用該激活實(shí)例化器的newInsta
nce 方法。
如果對(duì)象組描述符的激活實(shí)例化器(組)還不存在,則激活器將啟動(dòng)新的 Activ
ationInstantiator 化身執(zhí)行進(jìn)程(例如通過(guò)生成子進(jìn)程)。當(dāng)激活器為某一組
重建 ActivationInstantiator 時(shí),它必須將該組的化身數(shù)增一。注意,化身數(shù)
從 0 開(kāi)始。激活系統(tǒng)用化身數(shù)來(lái)檢測(cè)后來(lái)的 ActivationSystem.activeGroup 和
ActivationMonitor.inactiveGroup 調(diào)用。激活系統(tǒng)將棄去那些化身數(shù)小于組的
當(dāng)前數(shù)的調(diào)用。
----------------------------------------------------------------------
----------
注意 - 激活器在啟動(dòng)新的激活組時(shí)必須與激活組的標(biāo)識(shí)符、描述符及化身數(shù)進(jìn)行
通訊。激活器將在一個(gè)獨(dú)立的虛擬機(jī)中(例如作為一個(gè)獨(dú)立的進(jìn)程或子進(jìn)程)生
成激活組。因此,它必須將信息傳遞過(guò)去,以指定用 ActivationGroup.createG
roup 方法來(lái)創(chuàng)建該組時(shí)所需的信息。激活器并未指定如何將此信息傳給所生成的
進(jìn)程??捎靡丫幗M對(duì)象的形式將此信息送到子進(jìn)程的標(biāo)準(zhǔn)輸入中。
----------------------------------------------------------------------
----------
當(dāng)激活器接收到激活組的回調(diào)(通過(guò) ActivationSystem.activeGroup 方法,該
回調(diào)可指明激活組的引用和化身數(shù))時(shí),激活器就可以調(diào)用該激活實(shí)例化器的 n
ewInstance 方法,從而將每個(gè)待定的激活請(qǐng)求轉(zhuǎn)發(fā)給該激活實(shí)例化器,同時(shí)將結(jié)
果(一個(gè)已編組遠(yuǎn)程對(duì)象引用、一個(gè) stub)返給每個(gè)調(diào)用程序。
注意,激活器接收的是 MarshalledObject 對(duì)象而不是 Remote 對(duì)象。因此,激
活器不需要加載該對(duì)象的代碼,也不需要參與該對(duì)象的分布式垃圾收集。如果激
活器保留了對(duì)遠(yuǎn)程對(duì)象的強(qiáng)引用,則該激活器將防止該對(duì)象在正常的分布式垃圾
收集機(jī)制下被當(dāng)作垃圾而收集。
如果激活失敗,activate 方法將拋出 ActivationException。激活可能會(huì)因以下
各種原因而失?。赫也坏筋?lèi)、無(wú)法與激活組取得聯(lián)系等。如果先前沒(méi)有為激活標(biāo)
識(shí)符 id 向該激活器注冊(cè)激活描述符,則 activate 方法將拋出 UnknownObject
Exception。如果對(duì)該激活器的遠(yuǎn)程調(diào)用失敗,則拋出 RemoteException。
7.4.2 ActivationSystem 接口
ActivationSystem 提供了一種為組和可激活對(duì)象(這些對(duì)象將在這些組中被激活
)注冊(cè)的方法。 ActivationSystem 與 Activator 和 ActivationMonitor 都能
密切合作。前者負(fù)責(zé)激活通過(guò) ActivationSystem 所注冊(cè)的對(duì)象;后者負(fù)責(zé)獲取
活動(dòng)對(duì)象、非活動(dòng)對(duì)象及非活動(dòng)組的有關(guān)信息。
package java.rmi.activation;
public interface ActivationSystem extends java.rmi.Remote
{
public static final int SYSTEM_PORT = 1098;
ActivationGroupID registerGroup(ActivationGroupDesc desc)
throws ActivationException, java.rmi.RemoteException;
ActivationMonitor activeGroup(ActivationGroupID id,
ActivationInstantiator group,
long incarnation)
throws UnknownGroupException, ActivationException,
java.rmi.RemoteException;
void unregisterGroup(ActivationGroupID id)
throws ActivationException, UnknownGroupException,
java.rmi.RemoteException;
ActivationID registerObject(ActivationDesc desc)
throws ActivationException, UnknownGroupException,
java.rmi.RemoteException;
void unregisterObject(ActivationID id)
throws ActivationException, UnknownObjectException,
java.rmi.RemoteException;
void shutdown() throws java.rmi.RemoteException;
}
----------------------------------------------------------------------
----------
注意 - 作為一種安全措施,以上所有方法(registerGroup、activeGroup、unr
egisterGroup、registerObject、unregisterObject 和 shutdown)如果被客戶(hù)
機(jī)所調(diào)用,且該客戶(hù)機(jī)所處主機(jī)與激活系統(tǒng)不同,則將拋出 java.rmi.AccessEx
ception。該異常是 java.rmi.RemoteException 的子類(lèi)。
----------------------------------------------------------------------
----------
registerObject 方法用來(lái)注冊(cè)激活描述符 desc,同時(shí)也為可激活遠(yuǎn)程對(duì)象獲取
激活標(biāo)識(shí)符。 ActivationSystem 為描述符 desc 所指定的對(duì)象創(chuàng)建 Activatio
nID(激活標(biāo)識(shí)符),并將激活描述符及其關(guān)聯(lián)的標(biāo)識(shí)符記錄在穩(wěn)定的存儲(chǔ)庫(kù)中以
備將來(lái)使用。當(dāng) Activator 接到某個(gè)特定標(biāo)識(shí)符的 activate 請(qǐng)求時(shí),它就查找
該指定標(biāo)識(shí)符的激活描述符(先前已注冊(cè)),并用此信息來(lái)激活該對(duì)象。如果 d
esc 中所引用的組并沒(méi)有向該系統(tǒng)注冊(cè),則該方法將拋出 UnknownGroupExcepti
on。如果注冊(cè)失?。ɡ?,數(shù)據(jù)庫(kù)更新失敗等),則拋出 ActivationException
。如果遠(yuǎn)程調(diào)用失敗, 則拋出 RemoteException。
unregisterObject 方法用于刪除激活標(biāo)識(shí)符 id 及以前向 ActivationSystem 注
冊(cè)過(guò)的相關(guān)描述符。該調(diào)用完成后,就不能再用對(duì)象的激活 id 來(lái)激活該對(duì)象。
如果對(duì)象的 id 是未知的(沒(méi)有被注冊(cè)),則該方法將拋出 UnknownObjectExce
ption。如果注銷(xiāo)失?。ɡ?,數(shù)據(jù)庫(kù)的更新失敗等),則該方法將拋出 Activa
tionException。如果遠(yuǎn)程調(diào)用失敗,則拋出 RemoteException。
registerGroup 方法用于向激活系統(tǒng)注冊(cè)組描述符 desc 所指定的激活組,并返
回指派給該組的 ActivationGroupID。必須先向 ActivationSystem 注冊(cè)激活組
,然后才能在該組中注冊(cè)對(duì)象。 如果組的注冊(cè)失敗,則該方法將拋出 Activati
onException。如果遠(yuǎn)程調(diào)用失敗,則拋出 RemoteException。
activeGroup 方法是來(lái)自 ActivationGroup(具有標(biāo)識(shí)符 id)的回調(diào),用以通知
激活系統(tǒng)下列信息:組現(xiàn)在是活動(dòng)的,而且也是該虛擬機(jī)的 ActivationInstant
iator。此回調(diào)是在 ActivationGroup.createGroup 方法內(nèi)部進(jìn)行的,可以獲取
ActivationMonitor。組將用該 ActivationMonitor 就對(duì)象和組的狀態(tài)(即該組
內(nèi)的組和對(duì)象已變?yōu)榉腔顒?dòng)的)對(duì)系統(tǒng)進(jìn)行更新。 如果該組沒(méi)有被注冊(cè),則拋出
UnknownGroupException。如果該組已是活動(dòng)的,則拋出 ActivationException
。如果對(duì)激活系統(tǒng)的遠(yuǎn)程調(diào)用失敗,則拋出 RemoteException。
unregisterGroup 方法將具有標(biāo)識(shí)符 id 的激活組從激活系統(tǒng)中刪掉。激活組將
進(jìn)行此回調(diào),以通知激活器應(yīng)該將該組銷(xiāo)毀。如果此調(diào)用順利完成,就將無(wú)法再
在該組內(nèi)注冊(cè)和激活對(duì)象。有關(guān)該組及其相關(guān)對(duì)象的所有信息都將從系統(tǒng)中刪掉
。如果該組是未經(jīng)注冊(cè)的,則該方法將拋出 UnknownGroupException。如果遠(yuǎn)程
調(diào)用失敗,則拋出 RemoteException。如果注銷(xiāo)失?。ㄈ鐢?shù)據(jù)庫(kù)更新失敗等),
則拋出 ActivationException。
shutdown 方法將以適當(dāng)?shù)漠惒椒绞浇K止激活系統(tǒng)和所有有關(guān)的激活進(jìn)程(激活器
、監(jiān)控器及組)。由激活守護(hù)進(jìn)程所生成的所有組都將被銷(xiāo)毀,激活守護(hù)進(jìn)程也
將退出。要關(guān)閉激活系統(tǒng)守護(hù)進(jìn)程 rmid,請(qǐng)執(zhí)行命令:
rmid -stop [-端口號(hào)]
該命令將關(guān)閉指定端口上的激活守護(hù)進(jìn)程(如果沒(méi)有指定端口,則將關(guān)閉缺省端
口上的守護(hù)進(jìn)程)。
7.4.3 ActivationMonitor 類(lèi)
ActivationMonitor 是 ActivationGroup 特有的,它可通過(guò)調(diào)用 ActivationSy
stem.activeGroup 以報(bào)告某個(gè)組時(shí)獲得(這種調(diào)用是在 ActivationGroup.crea
teGroup 方法內(nèi)部進(jìn)行的)。激活組在出現(xiàn)以下情況時(shí)負(fù)責(zé)通知 ActivationMon
itor:它的對(duì)象已變成活動(dòng)對(duì)象、非活動(dòng)對(duì)象或該組已整個(gè)變成非活動(dòng)。
package java.rmi.activation;
public interface ActivationMonitor extends java.rmi.Remote
{
public abstract void inactiveObject(ActivationID id)
throws UnknownObjectException, RemoteException;
public void activeObject(ActivationID id,
java.rmi.MarshalledObject mobj)
throws UnknownObjectException, java.rmi.RemoteException;
public void inactiveGroup(ActivationGroupID id, long incarnation)
throws UnknownGroupException, java.rmi.RemoteException;
}
當(dāng)激活組中的某個(gè)對(duì)象變成非活動(dòng)(停用)時(shí),該激活組將調(diào)用其監(jiān)控器的 ina
ctiveObject 方法。激活組通過(guò)調(diào)用它的 inactiveObject 方法來(lái)發(fā)現(xiàn)其虛擬機(jī)
中的對(duì)象(該對(duì)象參與了激活)是否已為非活動(dòng)狀態(tài)。
inactiveObject 調(diào)用將通知 ActivationMonitor 其所保留的、具有激活標(biāo)識(shí)符
id 的對(duì)象的遠(yuǎn)程對(duì)象引用已不再有效。監(jiān)控器將把與 id 關(guān)聯(lián)的引用視為已過(guò)
時(shí)。由于該引用被當(dāng)成過(guò)時(shí)引用,因此后面為同一激活標(biāo)識(shí)符所進(jìn)行的 activat
e 調(diào)用將導(dǎo)致遠(yuǎn)程對(duì)象被重新激活。如果該對(duì)象對(duì) ActivationMonitor 未知,該
方法將拋出 UnknownObjectException。如果遠(yuǎn)程調(diào)用失敗,則拋出 RemoteExce
ption。
activeObject 調(diào)用通知 ActivationMonitor 與 id 相關(guān)聯(lián)的對(duì)象現(xiàn)在是活動(dòng)的
。參數(shù) obj 是該對(duì)象的 stub 的編組表述。 如果組中的某個(gè)對(duì)象是通過(guò)其它方
法被激活的,而不是由系統(tǒng)直接激活的(也就是說(shuō),對(duì)象被注冊(cè)并自己“激活”
自己),則 ActivationGroup 必須通知其監(jiān)控器。如果該對(duì)象的標(biāo)識(shí)符先前沒(méi)有
被注冊(cè),則該方法將拋出 UnknownObjectException。如果遠(yuǎn)程調(diào)用失敗,則拋出
RemoteException。
inactiveGroup 調(diào)用通知監(jiān)控器由 id 和 incarnation 所指定的組現(xiàn)在已非活動(dòng)
。一旦下一個(gè)要求在該組內(nèi)激活對(duì)象的請(qǐng)求出現(xiàn)時(shí),將用一個(gè)更大的化身數(shù)來(lái)重
新創(chuàng)建該組。當(dāng)組中所有對(duì)象都報(bào)告說(shuō)它們已非活動(dòng)對(duì)象時(shí),該組即變成非活動(dòng)
組。如果該組的 id 沒(méi)有被注冊(cè),或者化身數(shù)比該組當(dāng)前的化身數(shù)更小,則該方
法將拋出 UnknownGroupException。如果遠(yuǎn)程調(diào)用失敗,則拋出 RemoteExcepti
on。
7.4.4 ActivationInstantiator 類(lèi)
ActivationInstantiator 負(fù)責(zé)創(chuàng)建可激活對(duì)象的實(shí)例。ActivationGroup 的具體
子類(lèi)實(shí)現(xiàn) newInstance 方法,以便對(duì)在組內(nèi)創(chuàng)建對(duì)象的過(guò)程進(jìn)行控制。
package java.rmi.activation;
public interface ActivationInstantiator extends java.rmi.Remote
{
public MarshalledObject newInstance(ActivationID id,
ActivationDesc desc)
throws ActivationException, java.rmi.RemoteException;
}
為了在該組內(nèi)重新創(chuàng)建具有激活標(biāo)識(shí)符 id、描述符 desc 的對(duì)象,激活器需要調(diào)
用實(shí)例化器的 newInstance 方法。實(shí)例化器負(fù)責(zé):
用描述符的 getClassName 方法來(lái)決定對(duì)象的類(lèi);
從由描述符中所獲得的 cadebase 路徑中加載對(duì)象的類(lèi)(用 getLocation 方法)
;
通過(guò)調(diào)用對(duì)象的類(lèi)的特殊“激活”構(gòu)造函數(shù)創(chuàng)建該類(lèi)的實(shí)例。這種特殊構(gòu)造函數(shù)
帶有兩個(gè)參數(shù):一個(gè)是對(duì)象的 ActivationID,另一個(gè)是含有對(duì)象特有的初始化數(shù)
據(jù)的 MarshalledObject;
返回一個(gè)含有它所創(chuàng)建的遠(yuǎn)程對(duì)象的 MarshalledObject。
實(shí)例化器還負(fù)責(zé)在它所創(chuàng)建或激活的對(duì)象不再是活動(dòng)對(duì)象時(shí)進(jìn)行報(bào)告,因此可以
對(duì)其 ActivationMonitor 執(zhí)行相應(yīng)的 inactiveObject 調(diào)用(詳細(xì)信息,參見(jiàn)
ActivationGroup 類(lèi))。
如果對(duì)象的激活失敗, newInstance 方法將拋出 ActivationException。如果遠(yuǎn)
程調(diào)用失敗,則該方法將拋出 RemoteException。
7.4.5 ActivationGroupDesc 類(lèi)
激活組描述符 ActivationGroupDesc 含有創(chuàng)建或重新創(chuàng)建激活組(將在該激活組
中激活相同 Java 虛擬機(jī)上的對(duì)象)所需的信息。
這種描述符含有:
組的類(lèi)名,
組的 cadebase 路徑(組的類(lèi)所在位置),
“已編組”對(duì)象,它可包含對(duì)象特定的初始化數(shù)據(jù)。
對(duì)象的類(lèi)必須是 ActivationGroup 的具體子類(lèi)。ActivationGroup 的子類(lèi)是用
ActivationGroup.createGroup 靜態(tài)方法來(lái)創(chuàng)建或重新創(chuàng)建的,該靜態(tài)方法將調(diào)
用含有以下兩個(gè)參數(shù)的特殊構(gòu)造函數(shù):
該組的 ActivationGroupID,
該組的初始化數(shù)據(jù)(在 java.rmi.MarshalledObject 中)
package java.rmi.activation;
public final class ActivationGroupDesc implements java.io.Serializable
{
public ActivationGroupDesc(java.util.Properties props,
CommandEnvironment env);;
public ActivationGroupDesc(String className,
String codebase,
java.rmi.MarshalledObject data,
java.util.Properties props,
CommandEnvironment env);
public String getClassName();
public String getLocation();
public java.rmi.MarshalledObject getData();
public CommandEnvironment getCommandEnvironment();
public java.util.Properties getPropertiesOverrides();
}
第一個(gè)構(gòu)造函數(shù)將創(chuàng)建一個(gè)組描述符,它用系統(tǒng)的缺省值來(lái)作為組的實(shí)現(xiàn)和代碼
位置。各屬性指定了 Java 環(huán)境覆蓋(它將覆蓋組實(shí)現(xiàn)虛擬機(jī)中的系統(tǒng)屬性)。
命令環(huán)境可控制啟動(dòng)子虛擬機(jī)時(shí)所用的確切命令/選項(xiàng),也可為 null 以接受 rm
id 的缺省值。
第二個(gè)構(gòu)造函數(shù)和第一個(gè)相同,但它允許指定 Properties 和 CommandEnvironm
ent。
getClassName 方法返回組的類(lèi)名。
getLocation 方法返回 cadebase 路徑,從中可加載該組的類(lèi)。
getData 方法以編組形式返回組的初始化數(shù)據(jù)。
getCommandEnvironment 方法返回命令環(huán)境(可能為 null)。
getPropertiesOverrides 方法返回該描述符的屬性覆蓋(可能為 null)。
7.4.6 ActivationGroupDesc.CommandEnvironment 類(lèi)
CommandEnvironment 類(lèi)允許對(duì)缺省系統(tǒng)屬性進(jìn)行覆蓋,并可為 ActivationGrou
p 指定由實(shí)現(xiàn)所定義的選項(xiàng)。
public static class CommandEnvironment
implements java.io.Serializable
{
public CommandEnvironment(String cmdpath, String[] args);
public boolean equals(java.lang.Object);
public String[] getCommandOptions();
public String getCommandPath();
public int hashCode();
}
構(gòu)造函數(shù)將用所給的命令 cmdpath 和另一個(gè)命令行選項(xiàng) args 創(chuàng)建 CommandEnv
ironment。
equals 實(shí)現(xiàn)對(duì)命令環(huán)境對(duì)象的內(nèi)容等效操作。對(duì) hashCode 方法進(jìn)行適當(dāng)?shù)膶?shí)現(xiàn)
可在必要時(shí)將 CommandEnvironment 對(duì)象儲(chǔ)存在散列表中。
getCommandOptions 方法返回環(huán)境對(duì)象的命令行選項(xiàng)。
getCommandPath 方法返回環(huán)境對(duì)象的命令字符串。
7.4.7 ActivationGroupID 類(lèi)
注冊(cè)過(guò)的激活組的標(biāo)識(shí)符可有以下幾個(gè)用途:
在激活系統(tǒng)中對(duì)該組進(jìn)行唯一標(biāo)識(shí)
含有對(duì)該組的激活系統(tǒng)的引用,因而必要時(shí)該組能與其激活系統(tǒng)聯(lián)系。
ActivationGroupID 將在調(diào)用 ActivationSystem.registerGroup 時(shí)被返回,并
用來(lái)在該激活系統(tǒng)內(nèi)標(biāo)識(shí)該組。當(dāng)創(chuàng)建或重新創(chuàng)建激活組時(shí),該組標(biāo)識(shí)符將被作
為參數(shù)傳給激活組的特殊構(gòu)造函數(shù)。
package java.rmi.activation;
public class ActivationGroupID implements java.io.Serializable
{
public ActivationGroupID(ActivationSystem system);
public ActivationSystem getSystem();
public boolean equals(Object obj);
public int hashCode();
}
ActivationGroupID 構(gòu)造函數(shù)創(chuàng)建唯一的組標(biāo)識(shí)符。該標(biāo)識(shí)符的 ActivationSys
tem 是 system。
getSystem 方法返回組的激活系統(tǒng)。
hashCode 方法返回組標(biāo)識(shí)符的散列碼。兩個(gè)指向同一遠(yuǎn)程組的組標(biāo)識(shí)符將具有相
同的散列碼。
equals 方法比較兩個(gè)組標(biāo)識(shí)符內(nèi)容的等效性。如果以下兩個(gè)條件均成立,該方法
將返回 true: 1) 兩個(gè)唯一標(biāo)識(shí)符在內(nèi)容上等價(jià)。2) 各標(biāo)識(shí)符中指定的激活系
統(tǒng)都引用同一遠(yuǎn)程對(duì)象。
7.4.8 ActivationGroup 類(lèi)
ActivationGroup 負(fù)責(zé)在其組中創(chuàng)建“可激活”對(duì)象的新實(shí)例,并在出現(xiàn)下列情
況時(shí)通知其 ActivationMonitor: 其對(duì)象變成活動(dòng)或非活動(dòng),或者該組整體變成
非活動(dòng)。
ActivationGroup 最初是由以下方法之一創(chuàng)建的:
作為創(chuàng)建對(duì)象的“缺省” ActivationDesc 的副效應(yīng)而創(chuàng)建
通過(guò)對(duì) ActivationGroup.createGroup 方法的顯式調(diào)用而創(chuàng)建
作為在組(該組中僅 ActivationGroupDesc 被注冊(cè)過(guò))中激活第一個(gè)對(duì)象時(shí)的副
效應(yīng)而創(chuàng)建。
只有激活器才能重新創(chuàng)建 ActivationGroup。必要時(shí),激活器將為每個(gè)已注冊(cè)的
激活組生成一個(gè)獨(dú)立的虛擬機(jī)(例如作為子進(jìn)程)并將激活請(qǐng)求定向到相應(yīng)的組
。生成虛擬機(jī)的方式與實(shí)現(xiàn)有關(guān)。激活組是通過(guò) ActivationGroup.createGroup
靜態(tài)方法來(lái)創(chuàng)建的。createGroup 方法對(duì)即將創(chuàng)建的組有兩個(gè)要求: 1) 該組必
須是 ActivationGroup 的具體子類(lèi);2) 該組必須有一個(gè)取以下兩個(gè)參數(shù)的構(gòu)造
函數(shù):
該組的 ActivationGroupID,
該組的初始化數(shù)據(jù)(包含在 MarshalledObject中)
創(chuàng)建完畢,ActivationGroup 的缺省實(shí)現(xiàn)將在創(chuàng)建該組的 ActivationGroupDesc
時(shí)把系統(tǒng)屬性設(shè)置為強(qiáng)制系統(tǒng)屬性,并將安全管理器設(shè)置為 java.rmi.RMISecu
rityManager。如果應(yīng)用程序要求當(dāng)對(duì)象在組中被激活時(shí)設(shè)置某些特定的屬性,則
該應(yīng)用程序應(yīng)在創(chuàng)建 ActivationDesc 之前(缺省 ActivationGroupDesc 創(chuàng)建前
)設(shè)置這些屬性。
package java.rmi.activation;
public abstract class ActivationGroup
extends UnicastRemoteObject
implements ActivationInstantiator
{
protected ActivationGroup(ActivationGroupID groupID)
throws java.rmi.RemoteException;
public abstract MarshalledObject newInstance(ActivationID id,
ActivationDesc desc)
throws ActivationException, java.rmi.RemoteException;
public abstract boolean inactiveObject(ActivationID id)
throws ActivationException, UnknownObjectException,
java.rmi.RemoteException;
public static ActivationGroup createGroup(ActivationGroupID id,
ActivationGroupDesc desc,
long incarnation)
throws ActivationException;
public static ActivationGroupID currentGroupID();
public static void setSystem(ActivationSystem system)
throws ActivationException;
public static ActivationSystem getSystem()
throws ActivationException;
protected void activeObject(ActivationID id,
java.rmi.MarshalledObject mobj)
throws ActivationException, UnknownObjectException,
java.rmi.RemoteException;
protected void inactiveGroup()
throws UnknownGroupException, java.rmi.RemoteException;
}
激活器通過(guò)調(diào)用激活組的 newInstance 方法來(lái)激活具有激活描述符 desc 的對(duì)象
。激活組負(fù)責(zé):
利用描述符的 getClassName 方法來(lái)確定該對(duì)象的類(lèi);
通過(guò) getLocation 方法從由描述符中所得到的 URL 路徑中加載該類(lèi);
通過(guò)調(diào)用該對(duì)象類(lèi)的特殊構(gòu)造函數(shù)來(lái)創(chuàng)建該類(lèi)的實(shí)例。該構(gòu)造函數(shù)取以下兩個(gè)變
量:對(duì)象的 ActivationID 和含有對(duì)象初始化數(shù)據(jù)的 MarshalledObject;
將剛創(chuàng)建的遠(yuǎn)程對(duì)象的序列化版本返給激活器。
如果無(wú)法創(chuàng)建所給描述符的實(shí)例,該方法將拋出 ActivationException。
對(duì)該組的 inactiveObject 方法的調(diào)用是通過(guò)調(diào)用 Activatable.inactive 方法
來(lái)間接進(jìn)行的。當(dāng)遠(yuǎn)程對(duì)象停用時(shí)(該對(duì)象被認(rèn)為非活動(dòng)的),該對(duì)象的實(shí)現(xiàn)必
須調(diào)用 Activatable 的 inactive。如果對(duì)象在非活動(dòng)時(shí)不調(diào)用 Activatable.i
nactive,則該對(duì)象將永遠(yuǎn)不會(huì)被作為垃圾收集,因?yàn)榻M將對(duì)其所創(chuàng)建的對(duì)象保留
強(qiáng)引用。
組的 inactiveObject 方法可阻止從 RMI 運(yùn)行時(shí)中導(dǎo)出與 id 關(guān)聯(lián)的遠(yuǎn)程對(duì)象(
僅當(dāng)沒(méi)有對(duì)該對(duì)象的待定或正在執(zhí)行的調(diào)用時(shí))。使該對(duì)象將無(wú)法再接收到來(lái)的
RMI 調(diào)用。如果該對(duì)象當(dāng)前還有待定或正在執(zhí)行的調(diào)用,inactiveObject 將返
回 false 且不采取任何動(dòng)作。
如果 unexportObject 操作成功,意味著該對(duì)象沒(méi)有待定或正在執(zhí)行的調(diào)用。此
時(shí)組將通過(guò)監(jiān)控器的 inactiveObject 方法通知它的 ActivationMonitor 該遠(yuǎn)程
對(duì)象當(dāng)前是非活動(dòng)的,以便激活器在接到下一激活請(qǐng)求時(shí)即重新將該遠(yuǎn)程對(duì)象激
活。如果操作成功,inactiveObject 將返回 true。如果該對(duì)象被 ActivationG
roup 認(rèn)為是活動(dòng)的但已被阻止導(dǎo)出,操作將仍有可能成功。
如果激活組不知道該對(duì)象(例如該對(duì)象先前已被報(bào)告為是非活動(dòng)的,或者從未通
過(guò)該激活組來(lái)激活該對(duì)象),則 inactiveObject 方法將拋出 UnknownObjectEx
ception。如果非活動(dòng)操作失?。ɡ?,對(duì)激活器或激活組的遠(yuǎn)程調(diào)用失?。瑒t
將拋出 RemoteException。
createGroup 方法將為當(dāng)前虛擬機(jī)創(chuàng)建和設(shè)置激活組。只有在激活組是當(dāng)前未設(shè)
定的情況下才能對(duì)它進(jìn)行設(shè)置。當(dāng) Activator 為了執(zhí)行到來(lái)的 activate 請(qǐng)求而
啟動(dòng)某一激活組的重新創(chuàng)建過(guò)程時(shí),該激活組即通過(guò) createGroup 方法進(jìn)行設(shè)置
。組必須先向 ActivationSystem 注冊(cè)一個(gè)描述符,然后才能用該方法(將注冊(cè)
中得到的 ActivationID 傳給它)來(lái)創(chuàng)建該組。
由 ActivationGroupDesc(即 desc)指定的組必須是 ActivationGroup 的具體
子類(lèi)并具有公共構(gòu)造函數(shù)。該公共構(gòu)造函數(shù)取兩個(gè)參數(shù):一個(gè)是組的 Activatio
nGroupID;另一個(gè)是 MarshalledObject,它含有組的初始化數(shù)據(jù)(從組的Activ
ationGroupDesc 中獲得的)。注意: 如果應(yīng)用程序要?jiǎng)?chuàng)建自己的自定義激活組
,該組必須在構(gòu)造函數(shù)中設(shè)置安全管理器。否則將不能在該組中激活對(duì)象。
創(chuàng)建完組后,即通知 ActivationSystem 該組已通過(guò)調(diào)用 activeGroup 方法(該
方法將返回組的 ActivationMonitor)而被激活。應(yīng)用程序不必單獨(dú)調(diào)用 activ
eGroup,因?yàn)?nbsp;createGroup 方法將負(fù)責(zé)這一回調(diào)。
一旦組被創(chuàng)建,對(duì) currentGroupID 方法的后續(xù)調(diào)用都將返回該組的標(biāo)識(shí)符,直
到該組變成非活動(dòng)組為止。那時(shí),currentGroupID 方法將返回 null。
參數(shù) incarnation 表示當(dāng)前的組化身數(shù),也就是該組被激活的次數(shù)。一旦組被成
功創(chuàng)建,化身數(shù)就被用作 activeGroup 方法的參數(shù)。化身數(shù)從 0 開(kāi)始。如果該
組已經(jīng)存在,或在組的創(chuàng)建過(guò)程中出錯(cuò),createGroup 方法將拋出 ActivationE
xception。
setSystem 方法用于設(shè)置虛擬機(jī)的 ActivationSystem (system)。只有當(dāng)前沒(méi)有
組為活動(dòng)組時(shí)才能對(duì)激活系統(tǒng)進(jìn)行設(shè)置。如果沒(méi)有通過(guò)顯式調(diào)用 setSystem 來(lái)設(shè)
置激活系統(tǒng),則 getSystem 方法將嘗試通過(guò)在 Activator 的注冊(cè)服務(wù)程序中查
找名稱(chēng) java.rmi.activation.ActivationSystem 來(lái)獲得對(duì) ActivationSystem
的引用。缺省情況下,查找激活系統(tǒng)所用的端口號(hào)將由 ActivationSystem.SYST
EM_PORT 定義。通過(guò)設(shè)置屬性 java.rmi.activation.port 可將該端口覆蓋掉。
如果調(diào)用 setSystem 時(shí)激活系統(tǒng)已經(jīng)設(shè)置好,則該方法將拋出 ActivationExce
ption。
getSystem 方法返回該虛擬機(jī)的激活系統(tǒng)。激活系統(tǒng)可由 setSystem 方法(前述
)設(shè)置。
activeObject 方法是一個(gè)受保護(hù)的方法。子類(lèi)將用它來(lái)對(duì)組監(jiān)控器進(jìn)行 active
Object 回調(diào),以通知監(jiān)控器具有指定激活 id 且其 stub 包含在 mobj 中的遠(yuǎn)程
對(duì)象現(xiàn)在是活動(dòng)的。這一調(diào)用只是轉(zhuǎn)發(fā)給組的 ActivationMonitor。
inactiveGroup 方法是一個(gè)受保護(hù)的方法。子類(lèi)用它來(lái)通知組監(jiān)控器該組已變成
非活動(dòng)的。當(dāng)組中每個(gè)參與虛擬機(jī)中激活活動(dòng)的對(duì)象都變成非活動(dòng)時(shí),子類(lèi)就進(jìn)
行此調(diào)用。
7.4.9 MarshalledObject 類(lèi)
MarshalledObject 是某個(gè)對(duì)象的容器,它允許在進(jìn)行 RMI 調(diào)用時(shí)將該對(duì)象當(dāng)作
一個(gè)參數(shù)來(lái)傳遞,但它延遲該對(duì)象在接收端上的序列化恢復(fù),直到應(yīng)用程序明確
地請(qǐng)求該對(duì)象(通過(guò)調(diào)用該容器對(duì)象)。包含在該 MarshalledObject 中的可序
列化對(duì)象是用相同的語(yǔ)義(該語(yǔ)義作為 RMI 調(diào)用中的參數(shù)來(lái)傳遞)來(lái)序列化和序
列化恢復(fù)的(請(qǐng)求時(shí))。也就是說(shuō),MarshalledObject 中的任一遠(yuǎn)程對(duì)象都可表
示為其 stub 的序列化實(shí)例。MarshalledObject 所包含的對(duì)象可以是遠(yuǎn)程對(duì)象、
非遠(yuǎn)程對(duì)象或遠(yuǎn)程對(duì)象和非遠(yuǎn)程對(duì)象的完整圖形。
當(dāng)對(duì)象被放入 MarshalledObject 的 wrapper 中時(shí),該對(duì)象的序列化形式將被注
釋為 cadebase URL(可從中加載類(lèi));同樣,當(dāng)從對(duì)象的 MarshalledObject
的 wrapper 中取回該對(duì)象時(shí),如果本地沒(méi)有該對(duì)象的代碼,則使用該 URL(序列
化時(shí)所注解的)來(lái)定位和加載該對(duì)象類(lèi)的字節(jié)代碼。
package java.rmi;
public final class MarshalledObject implements java.io.Serializable
{
public MarshalledObject(Object obj) throws java.io.IOException;
public Object get()
throws java.io.IOException, ClassNotFoundException;
public int hashCode();
public boolean equals();
}
MarshalledObject 的構(gòu)造函數(shù)將可序列化的對(duì)象 obj 作為單一參數(shù),并將對(duì)象
的編組表示存放在字節(jié)流中。對(duì)象的編組表示保存了對(duì)象在 RMI 調(diào)用時(shí)所傳遞的
語(yǔ)義:
流中的每個(gè)類(lèi)都被注解為其 cadebase URL,以便在重構(gòu)該對(duì)象(通過(guò)調(diào)用 get
方法)時(shí)可以找到各個(gè)類(lèi)的字節(jié)代碼并進(jìn)行加載;
遠(yuǎn)程對(duì)象由它們的代理服務(wù)器 stub 所代替。
當(dāng)把類(lèi) MarshalledObject 的實(shí)例寫(xiě)到 java.io.ObjectOutputStream 中時(shí),所
含對(duì)象的編組形式(在構(gòu)造中創(chuàng)建)亦被寫(xiě)到流中。因此,只有字節(jié)流才被序列
化。
當(dāng)從 java.io.ObjectInputStream 中讀取 MarshalledObject 時(shí),并不把所包含
的對(duì)象序列化恢復(fù)為一個(gè)具體對(duì)象;該對(duì)象將一直保持其編組表示,直到該已編
組對(duì)象的 get 方法被調(diào)用為止。
get 方法總是要用所含對(duì)象的編組形式來(lái)重新構(gòu)造該對(duì)象。內(nèi)部表示將用解編參
數(shù)(用于 RMI 調(diào)用)所用的語(yǔ)義來(lái)進(jìn)行序列化恢復(fù)。因此,對(duì)象表示的序列化恢
復(fù)將用嵌入對(duì)象序列化流中的 URL 注解來(lái)加載類(lèi)的代碼(如果本地沒(méi)有該代碼)
。
對(duì)象編組表示的 hashCode 與傳遞給構(gòu)造函數(shù)的對(duì)象相同。如果進(jìn)行比較的對(duì)象
的編組表示是等價(jià)的,則 equals 方法將返回 true。該 equals 方法所采用的比
較將忽略類(lèi)的 cadebase 注解,即除了序列化表示中各個(gè)類(lèi)的 cadebase 外,只
要兩個(gè)對(duì)象具有相同的序列化表示,則這兩個(gè)對(duì)象就是等價(jià)的。
凡是有該標(biāo)志的文章,都是該blog博主Caoer(草兒)原創(chuàng),凡是索引、收藏
、轉(zhuǎn)載請(qǐng)注明來(lái)處和原文作者。非常感謝。