程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> J2EE >> RMI規范--五

RMI規范--五

編輯:J2EE
RMI規范--第五章 服務器接口 java.rmi.server 包包含通常用於實現遠程對象的接口與類。 主題: RemoteObject 類 RemoteServer 類 UnicastRemoteObject 類 Unreferenced 接口 RMISecurityManager 類 RMIClassLoader 類 LoaderHandler 接口 RMI 套接字工廠 RMIFailureHandler 接口 LogStream 類 stub 和 skeleton 編譯器 5.1 RemoteObject 類 類 java.rmi.server.RemoteObject 將 java.lang.Object 行為實現於遠程 對象。實現方法 hashCode 和 equals 將允許將遠程對象引用存儲在散列表中 進行比較。如果兩個 Remote 對象引用同一個遠程對象,則方法 equals 的返 回值為 true。它負責比較遠程對象的遠程對象引用。 方法 toString 返回一個說明遠程對象的字符串。該字符串的內容和語法與實 現有關且可變。 Java.lang.Object 中的其它方法保留了它們的原始實現。


package java.rmi.server; 
public abstract class RemoteObject 
implements java.rmi.Remote, java.io.Serializable 
{ 
protected transIEnt RemoteRef ref; 
protected RemoteObject(); 
protected RemoteObject(RemoteRef ref); 
public RemoteRef getRef(); 
public static Remote toStub(java.rmi.Remote obj) 
throws Java.rmi.NoSuchObjectException; 
public int hashCode(); 
public boolean equals(Object obj); 
public String toString(); 
} 
因為 RemoteObject 是抽象類,所以無法實例化。因此,RemoteObject 的構 造函數必須從子類實現中調用。第一個 RemoteObject 構造函數將創建帶空的 遠程引用的 RemoteObject。第二個 RemoteObject 構造函數將創建帶給定遠 程引用 ref 的 RemoteObject。 方法 getRef 返回該遠程對象的遠程引用。 方法 toStub 返回一個遠程對象 obj 的 stub 並作為參數傳送。該操作僅在 已經導出遠程對象實現後才有效。如果找不到遠程對象的 stub,該方法就拋出 NoSuchObjectException。 5.1.1 RemoteObject 類覆蓋的對象方法 java.lang.Object 類中用於方法 equals、hashCode 和 toString 的缺省實 現不適用於遠程對象。因此,RemoteObject 類提供了這些方法在語義上更合適 於遠程對象的實現。 equals 和 hashCode 方法 為將遠程對象用作散列表中的主鍵,我們必須在遠程對象實現中覆蓋 equals 和 hashCode 方法,這些方法是由類 java.rmi.server.RemoteObject 覆蓋的: java.rmi.server.RemoteObject 類實現 equals 方法決定了兩個對象的引用 是否相等,而不是兩個對象的內容是否相等。這是因為決定內容是否相等時需要 遠程方法調用,而 equals 的簽名不允許拋出遠程異常。 對於所有引用同一底層遠程對象的遠程引用,java.rmi.server.RemoteObject 類實現的 hashCode 方法返回同一個值(因為對相同對象的引用被認為是相等 的)。 toString 方法 toString 方法被定義為返回表示對象的遠程引用的字符串。字符串的內容視引 用的類型而定。單體(單路傳送)對象的當前實現一個對象標識符以及與傳輸層 有關的該對象的其他信息(例如主機名和端口號)。 clone 方法 只有在對象支持 java.lang.Cloneable 接口時才能用 Java 語言的缺省機制 來復制。由 rmic 編譯器生成的遠程對象的 stub 將被聲明為終態,且不實現 Cloneable 接口,因此無法復制 stub。 5.1.2 序列化形式 RemoteObject 類實現專門的(私用)方法 writeObject 和方法 readObject, 它們由對象序列化機制調用來處理向 java.io.ObjectOutputStream 中序列化 數據。RemoteObject 的序列化形式由下列方法寫入: private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException, java.lang.ClassNotFoundException; 如果 RemoteObject 的遠程引用域 ref 為空,則該方法拋出 java.rmi.MarshalException。 如果遠程引用 ref 為非空: ref 的類通過調用其 getRefClass 方法來獲得,該方法通常返回遠程引用類的 非打包全名。如果返回的類名為非空: ref 的類名將以 UTF 格式寫到流 out 中。 調用 ref 的方法 writeExternal,傳遞的參數為流 out,從而使 ref 可以將 其外部表示法寫到流中。 如果 ref.getRefClass 返回的類名為空: 則將一個 UTF 格式的空字符串寫到流 out 中。 ref 被序列化到流 out(即利用 writeObject)。 序列化恢復時,RemoteObject 的狀態將由 ObjectInputStream 調用該方法利 用其序列化形式進行重構: private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException; 首先,ref 的類名(UTF 字符串)將從流 in 中讀出。如果類名為空字符串: 則從流中讀出對象,然後將 ref 初始化為該對象(即通過調用 in.readObject) 如果類名為非空: 則 ref 的完整類名由字符串 java.rmi.server.RemoteRef.packagePrefix 的 值和“.”加上從流中讀取的類名相連接而成。 創建 ref 類的實例(利用上述完整類名)。 該新實例(成為 ref 域)從流 in 中讀取其外部形式。 2 RemoteServer 類 java.rmi.server.RemoteServer 類是服務器實現類 java.rmi.server.UnicastRemoteObject 和 Java.rmi.activation.Activatable 的通用超類。


package java.rmi.server; 
public abstract class RemoteServer extends RemoteObject 
{ 

protected RemoteServer(); 
protected RemoteServer(RemoteRef ref); 

public static String getClIEntHost() 
throws ServerNotActiveException; 
public static void setLog(java.io.OutputStream out); 
public static Java.io.PrintStream getLog(); 
} 
因為 RemoteServer 是抽象類,所以將無法實例化。因此,必須從子類實現中 調用某一 RemoteServer 的構造函數。第一個 RemoteServer 構造函數將創建 帶空遠程引用的 RemoteServer。第二個 RemoteServer 構造函數將創建帶給 定遠程引用 ref 的 RemoteServer。 getClIEntHost 方法允許一個活動方法確定當前線程中活動的遠程方法是由哪 台主機初始化的。如果當前線程中沒有活動的遠程方法,則拋出異常 ServerNot ActiveException。 setLog 方法將 RMI 調用記錄到指定輸出流中。如果輸出流為空,則關閉調用 日志。getLog 方法返回 RMI 調用日志流,從而使特定於應用程序的信息以同 步方式寫到調用日志中。 5.3 UnicastRemoteObject 類 類 Java.rmi.server.UnicastRemoteObject 支持創建並導出遠程對象。該類 實現的遠程服務器對象具有下列特征: 對這種對象的引用至多僅在創建該遠程對象的進程生命期內有效。 通過 TCP 傳輸與遠程對象通信。 調用、參數和結果使用流協議在客戶機和服務器之間進行通信。

package java.rmi.server; 
public class UnicastRemoteObject extends RemoteServer 
{ 

protected UnicastRemoteObject() 
throws java.rmi.RemoteException; 
protected UnicastRemoteObject(int port) 
throws java.rmi.RemoteException; 
protected UnicastRemoteObject(int port, 
RMIClientSocketFactory csf, 
RMIServerSocketFactory ssf) 
throws java.rmi.RemoteException; 
public Object clone() 
throws java.lang.CloneNotSupportedException; 
public static RemoteStub exportObject(java.rmi.Remote obj) 
throws java.rmi.RemoteException; 
public static Remote exportObject(java.rmi.Remote obj, int port) 
throws java.rmi.RemoteException; 
public static Remote exportObject(Remote obj, int port, 
RMIClIEntSocketFactory csf, 
RMIServerSocketFactory ssf) 
throws java.rmi.RemoteException; 
public static boolean unexportObject(java.rmi.Remote obj, boolean force) 
throws Java.rmi.NoSuchObjectException; 
} 
  5.3.1 構造新遠程對象 遠程對象實現(實現一個或多個遠程接口的實現)必須被創建和導出。導出遠程 對象使得對象能接受來自客戶機的到來的調用。作為 UnicastRemoteObject 導出的遠程對象,其導出涉及在 TCP 端口監聽(注意,多個遠程對象可以接受 同一端口的到來的調用,因此沒必要在新的端口上監聽)。遠程對象實現可以擴 展類 UnicastRemoteObject 以使用其導出對象的構造函數,或者擴展其它類 (或者根本不擴展)並通過 UnicastRemoteObject 的 exportObject 方法導 出對象。 無參數的構造函數將創建遠程對象並在匿名(或任意)端口上導出,而這將在運 行時進行選擇。第二種形式的構造函數帶單個參數(即 port),它指定遠程對 象接受到來的調用的端口號。第三種構造函數創建的遠程對象在指定端口上通過 RMIServerSocketFactory 創建的 ServerSocket 接受到來的調用;客戶機 通過由 RMIClientSocketFactory 提供的 Socket 與遠程對象建立連接。 5.3.2 導出並非由 RemoteObject 擴展而來的實現 exportObject 方法(任何形式)可用於導出不是由擴展 UnicastRemoteObject 類實現的簡單對等遠程對象。第一種形式的 exportObject 方法帶單個參數 (即 obj),它是接受到來的 RMI 調用的遠程對象;該 exportObject 方法 在匿名(或任意)端口上導出遠程對象,而這將在運行時進行選擇。第二種形式 的 exportObject 方法帶兩個參數,分別是遠程對象 obj 和 port。port 是 遠程對象接受到來的調用的端口號。第三種 exportObject 方法用指定的 RMIClIEntSocketFactory、csf 和 RMIServerSocketFactory、ssf 在指定 port 上導出對象 obj。 在作為參數或返回值傳入 RMI 調用前,必須導出對象,否則當試圖把“未導出 的”對象作為參數或返回值傳遞給一個遠程調用時,將會拋出 java.rmi.server.StubNotFoundException。 導出後,對象既可作為參數傳入 RMI 調用,也可作為 RMI 調用的結果返回。 exportObject 方法返回 Remote stub。它是遠程對象的 stub 對象 obj,它 將替代遠程對象被傳入 RMI 調用。 5.3.3 在 RMI 調用中傳遞 UnicastRemoteObject 如上所述,當類型為 UnicastRemoteObject 的對象作為參數或返回值傳入 RMI 調用中時,該對象將由遠程對象的 stub 所代替。遠程對象實現保留在創 建它的虛擬機中,且不會移出(包括其值)。換言之,遠程對象通過引用傳入 RMI 調用;遠程對象實現不能通過值進行傳遞。 5.3.4 序列化 UnicastRemoteObject 如果 UnicastRemoteObject 類型的對象寫入用戶定義的 ObjectOutputStream 例如,該對象寫入使用序列化的文件),則其中所含的信息將是瞬態的且未予保 存。但如果對象是用戶定義的 UnicastRemoteObject 子類實例,它就能擁有 非瞬態數據並可在序列化對象時予以保存。 當 UnicastRemoteObject 從 ObjectInputStream 讀出時,它將自動導出到 RMI 運行時,以便接收 RMI 調用。如果由於某種原因而導致導出失敗,則序列 化恢復對象過程將予以終止,同時拋出異常。 5.3.5 逆導出 UnicastRemoteObject unexportObject 方法使遠程對象 obj 無法接受到來的調用。如果強制參數為 真,則即使有對遠程對象的待定調用或當前調用,該遠程對象仍將被強制逆導出。 如果強制參數為假,則僅在無對該對象的待定調用和當前調用時才逆導出該對象 。如果對象被成功地逆導出,則運行時將把該對象從內部表中刪除。以這種強制 方式逆導出對象可能導致客戶機持有該遠程對象的過期遠程引用。如果遠程對象 先前並未導出到 RMI 運行時中,則該方法將拋出異常 java.rmi.NoSuchObjectException。 5.3.6 clone 方法 只有支持 java.lang.Cloneable 接口的對象才可使用 Java 語言的缺省機制 復制。類 Java.rmi.server.UnicastRemoteObject 並不實現該接口,但它實 現 clone 方法以便當子類需要實現 Cloneable 時遠程對象可以正確地進行復 制。clone 方法可由子類用於創建一個初始內容相同的復制的遠程對象。但是 可以被導出接受遠程調用且與原對象有所不同。 5.4 Unreferenced 接口

package Java.rmi.server; 
public interface Unreferenced 
{ 
public void unreferenced(); 
} 
Java.rmi.server.Unreferenced 接口允許服務器對象通知,告訴它沒有客戶 機對它進行遠程引用。分布式垃圾收集機制將為每個遠程對象維護一個持有該遠 程對象引用的客戶虛擬機集合。只要某個客戶機持有該遠程對象的遠程引用, RMI 運行時就會保存該遠程對象的本地引用。當“引用”集合為空時,即調用 Unreferenced.unreferenced 方法(如果服務器實現 Unreferenced 接口)。 遠程對象不需要支持 Unreferenced 接口。 只要存在遠程對象的某個本地引用,它就可以在遠程調用中傳遞或返給客戶機。 接收引用的進程將被添加到遠程對象的引用集合中。當引用集合為空時,即調用 遠程對象的 unreferenced 方法。這樣,Unreferenced 方法可以進行多次調 用(每當集合為空時)。當不再有引用(本地引用或客戶機持有的引用)時,才 會收集遠程對象。 5.5 RMISecurityManager 類

package java.rmi; 

public class RMISecurityManager extends Java.lang.SecurityManager 
{ 
public RMISecurityManager(); 
public synchronized void checkPackageAccess(String pkg) 
throws RMISecurityException; 
} 
RMISecurityManager 提供與 java.lang.SecurityManager 相同的安全特性, 但它覆蓋 checkPackageAcess 方法。 在 RMI 應用程序中,如果沒有設置安全管理器,則只能從本地類路徑加載 stub 和類。這可確保應用程序不受由遠程方法調用所下載的代碼的侵害。 5.6 RMIClassLoader 類 Java.rmi.server.RMIClassLoader 類提供一套公共靜態方法,用於支持 RMI 中基於網絡的類加載。這些方法由 RMI 的內部編組流調用,用於實現 RMI 參數 和返回值類型的動態類加載。但為了模擬 RMI 的類加載行為,也可由應用程序 直接對其進行調用。RMIClassLoader 類沒有可以公共訪問的構造函數,因此無 法實例化。


package java.rmi.server; 

public class RMIClassLoader 
{ 
public static String getClassAnnotation(Class cl); 
public static Object getSecurityContext(ClassLoader loader); 
public static Class loadClass(String name) 
throws java.net.MalformedURLException, ClassNotFoundException; 
public static Class loadClass(String codebase, String name) 
throws java.net.MalformedURLException, ClassNotFoundException; 
public static Class loadClass(URL codebase, String name) 
throws Java.Net.MalformedURLException, ClassNotFoundException; 
} 

getClassAnnotation 方法將返回一個 String,該 String 代表網絡 codebase 路徑,遠程端點通過此路徑下載指定類的定義。RMI 運行時在內部 編組流中將使用由該方法返回的 String 對象作為類描述符的注解。該 codebase 字符串的格式是由空格界定的 codebase URL 字符串路徑。 返回的 codebase 字符串將依賴於所提供類的類加載器: 如果類加載器是下列之一: “系統類加載器”(用於加載應用程序“類路徑”中指定的類並從方法 ClassLoader.getSystemClassLoader 返回的類加載器), “系統類加載器”的父類,例如用於已安裝方式擴展的類加載器, 空值(用於加載虛擬機類的“自舉類加載器”),< 則返回 java.rmi.server.codebase 屬性的值。如果該屬性未設置則返回值為 null。 否則,如果類加載器是類 java.net.URLClassLoader 的實例,則返回的 codebase 字符串是一個以空格間隔的外部形式的 URL 列表,它由調用類加載 器上的 getURLs 方法返回。 如果 URLClassLoader 由 RMI 運行時創建用來 服務於一個 RMIClassLoader.loadClass 方法的調用,則無需任何許可就可獲 得相關的 codebase 字符串。 如果它是一個任意的 URLClassLoader 實例, 則調用程序必須擁有權限去連接 codebase 路徑中所有的 URL,在每個由 getURLs 方法返回的 URL 實例上調用 openConnection().getPermission() 來決定權限。 最後,如果類加載器不是 URLClassLoader 的實例,則 java.rmi.server.codebase 屬性值被返回,如果屬性值未設置,則返回 null。 因為 getSecurityContext 方法不再適用於 JDK1.2 安全模型,所以不鼓勵使 用它;它用於 JDK1.1 內部,用來實現基於類加載器的安全檢查。 如果指定的 類加載器是由 RMI 運行時創建用來服務於一個 RMIClassLoader.loadClass 方法的調用,則返回類加載器 codebase 路徑中第一個 URL;否則返回 null。 這三種 loadClass 方法都試圖通過使用當前線程的上下文類加載器,利用指定 的名稱加載類並且在設有安全管理器時為特定 codebase 路徑加載內部的 URLClassLoader: 只帶一個參數(類 name)的 loadClass 方法隱式使用 java.rmi.server.codebase 屬性值作為 codebase 路徑。我們不鼓勵使用該 版的 loadClass 方法,因為我們已不再鼓勵使用 java.rmi.server.codebase 屬性。用戶應使用下列更通用的版本。 帶有 String codebase 參數的 loadClass 方法將它用作 codebase 路徑; codebase 字符串必須是以空格間隔的其形式和 getClassAnnotation 方法返 回的相同 URL 列表。 帶有 Java.Net.URL codebase 參數的 loadClass 方法將單個 URL 用作 codebase。 對於所有 loadClass 方法,codebase 路徑將與當前線程的上下文類加載器 (通過在當前線程上調用 getContextClassLoader 來確定)一起使用,以確 定試圖用來加載類的內部類加載器實例。RMI 運行時將維持一個內部類加載器 實例表,以父類加載器和加載器的 codebase 路徑(一個有序 URL 列表)作為 鍵值。loadClass 方法以所需的 codebase 路徑和當前線程的上下文類加載器 為其父類,在表中查詢 URLClassLoader 實例。如果不存在該加載器,就會創 建一個並添加到表中。最後,將在所選類加載器上用指定的類 name 調用 loadClass 方法。 如果設有安全管理器(System.getSecurityManager 不返回 null),則 loadClass 的調用程序必須擁有能連到 codebase 路徑中所有 URL 的權限。 否則將拋出異常 ClassNotFoundException。為防止不受信任的代碼被加載到 沒有安全管理器的 Java 虛擬機中,在未設置安全管理器的情況下,所有 loadClass 方法都應忽略特定的 codebase 路徑,而只加載當前線程上下文類 加載器中指定 name 的類。 5.7 LoaderHandler 接口

package Java.rmi.server; 

public interface LoaderHandler 
{ 

Class loadClass(String name) 
throws MalformedURLException, ClassNotFoundException; 
Class loadClass(URL codebase,String name) 
throws MalformedURLException, ClassNotFoundException; 
Object getSecurityContext(ClassLoader loader); 
} 

-------------------------------------------------------------- 注意 - JDK1.2 中不鼓勵使用 LoaderHandler 接口。 -------------------------------------------------------------- LoaderHandler 接口僅由 JDK1.1 的內部 RMI 實現使用。 5.8 RMI 套接字工廠 當 RMI 運行時實現需要 java.net.Socket 和 java.net.ServerSocket 的實 例以用於連接時,它並非直接實例化這些類的對象,而是在當前 RMISocketFactory 對象(該對象由靜態方法 RMISocketFactory.getSocketFactory 返回)上調 用 createSocket 和 createServerSocket 方法。這將使應用程序可以用鉤子 來自定義 RMI 傳輸所用的套接字類型,例如 java.net.Socket 和 java.net.ServerSocket 類的子類。所用的 RMISocketFactory 實例可由可 信任的系統代碼設置一次。在 JDK 1.1 中,這種自定義被限制為關於套接字類 型的相對全局的決策,因為提供給工廠方法的參數只有主機和端口(對於 createSocket)及端口號(對於 createServerSocket)。 在 JDK 1.2 中,我們引入了新的接口 RMIServerSocketFactory 和 RMIClientSocketFactory,可更加靈活地自定義與遠程對象通訊所用的協議。 為使使用 RMI 的應用程序能利用這些新的套接字工廠接口,我們在 UnicastRemoteObject 和 java.rmi.activation.Activatable 中添加了幾 個新構造函數和 exportObject 方法,它們使用客戶機和服務器套接字工廠做 為附加參數。 由新構造函數或 exportObject 方法(以 RMIClientSocketFactory 和 RMIServerSocketFactory 為參數)導出的遠程對象將被 RMI 運行時區別對待 。在這種遠程對象的生命期內,運行時將用自定義 RMIServerSocketFactory 來創建 ServerSocket 以接受對遠程對象的到來的調用,同時用自定義 RMIClientSocketFactory 來創建 Socket 以連接客戶機和遠程對象。 由自定義套接字工廠導出的遠程對象 stub 和 skeleton 所用的 RemoteRef 和 ServerRef 實現分別是 UnicastRef2 和 UnicastServerRef2。UnicastRef2 類型的線表示法包含與 UnicastRef 類型不同的聯系“端點”的表示法(僅用 一個 UTF 格式的主機名字符串,後跟一個整型端口號表示)。對於 UnicastRef2,該端點的線表示則包括一個格式字節,用來指定端點表示的其余 內容(允許將來擴充),後跟的是指定格式的數據。當前,這些數據可包含 UTF 格式的主機名、端口號及可選的(由端點格式字節指定) RMIClientSocketFactory 對象序列化表示。它可被客戶機用於在該端點生成 到遠程對象的套接字連接。端點表示不包括在遠程對象導出時指定的 RMIServerSocketFactory 對象。 當通過 UnicastRef2 類型的引用進行調用時,運行時將在創建遠程對象的套 接字連接時使用端點中 RMIClientSocketFactory 對象的 createSocket 方 法。同樣,當運行時為了特定遠程對象進行 DGC "dirty" 和 "clean" 調用 時,它必須在遠程虛擬機上調用 DGC,方法是使用遠程引用中指定的同一 RMIClIEntSocketFactory 對象所生成的連接。服務器端的 DGC 實現應負責 驗證結果是否正確。 如果遠程對象是由老的構造函數或 UnicastRemoteObject 中沒有將自定義套 接字工廠作為參數的方法導出,則和以前一樣擁有 UnicastRef 和 UnicastServerRef 類型的 RemoteRef 和 ServerRef,並且其端點也將使用 老式線表示,即一個 UTF 格式的主機字符串跟一個指定端口號的整數。這樣那 些不使用 JDK 1.2 新特性的 RMI 服務器可以與老式 RMI 客戶機進行互操作。 5.8.1 RMISocketFactory 類 java.rmi.server.RMISocketFactory 抽象類提供一個接口來指定傳輸中如何 獲得套接字。注意,下面的類使用 Java.Net 包中的 Socket 和 ServerSocket。


package Java.rmi.server; 
public abstract class RMISocketFactory 
implements RMIClIEntSocketFactory, RMIServerSocketFactory 
{ 

public abstract Socket createSocket(String host, int port) 
throws IOException; 
public abstract ServerSocket createServerSocket(int port) 
throws IOException; 
public static void setSocketFactory(RMISocketFactory fac) 
throws IOException; 
public static RMISocketFactory getSocketFactory(); 
public static void setFailureHandler(RMIFailureHandler fh); 
public static RMIFailureHandler getFailureHandler(); 
} 
靜態方法 setSocketFactory 可用於設置套接字工廠,而 RMI 將從中獲得套接字 。應用程序用自己的實例 RMISocketFactory 僅能調用該方法一次。例如,應用 程序定義的 RMISocketFactory 實現在所要求的連接上做一些基本的過濾並拋出 異常,或者返回其對 java.net.Socket 或 Java.Net.ServerSocket 類的擴展( 例如提供安全信道的擴展)。注意,只有在當前安全管理器允許設置套接字工廠 時才可設置 RMISocketFactory。如果不允許進行該項設置,則將拋出 Security Exception。 靜態方法 getSocketFactory 返回由 RMI 使用的套接字工廠。如果未設置套接字 工廠,則返回值為 null。 當傳輸需要創建套接字時,傳輸層將在 getSocketFactory 方法返回的 RMISock etFactory 上調用 createSocket 和 createServerSocket 方法。例如: RMISocketFactory.getSocketFactory().createSocket(myhost, myport) 方法 createSocket 應創建一個連接到指定 host 和 port 的客戶機套接字。 c reateServerSocket 方法應在指定 port 上創建服務器套接字。 缺省的 RMISocketFactory 傳輸實現使用 HTTP 通過防火牆提供透明的 RMI,如 下所述: 在 createSocket 中,工廠將自動嘗試與無法用套接字直接聯系的主機建立 HTTP 連接。 在 createServerSocket 中,工廠將返回用於自動檢測新接受的連接是否為 HTT P POST 請求的服務器套接字。如果是,則返回僅將請求主體透明地展示給傳輸然 後將其輸出格式化為 HTTP 響應的套接字。 方法 setFailureHandler 設置失敗句柄。在創建服務器套接字失敗時,該句柄將 由 RMI 運行時調用。該句柄返回一個布爾值,用於指示是否應重試。缺省的失敗 句柄返回值為 false,意味著缺省情況下運行時將不再嘗試創建套接字。 方法 getFailureHandler 在套接字創建失敗時返回當前句柄。失敗句柄未設置時 將為 null。 5.8.2 RMIServerSocketFactory 接口 為了支持與遠程對象的自定義通信,可以在導出遠程對象時為其指定一個 RMISe rverSocketFactory 實例。這一點既可通過相應的 UnicastRemoteObject 構造函 數或 exportObject 方法完成,也可通過相應的 Java.rmi.activation.Activat able 構造函數或 exportObject 方法完成。如果該服務器套接字工廠在導出遠程 對象時與之關聯,則 RMI 運行時將使用遠程對象的服務器套接字工廠來創建 Se rverSocket(使用 RMIServerSocketFactory.createServerSocket 方法),以接 受遠程客戶機的連接。

package java.rmi.server; 
public interface RMIServerSocketFactory 
{ 

public Java.Net.ServerSocket createServerSocket(int port) 
throws IOException; 
} 
5.8.3 RMIClientSocketFactory 接口 要自定義與遠程對象的通信,可在導出時遠程對象為其指定一個 RMIClIEntSock etFactory 的實例。這一點既可通過相應的 UnicastRemoteObject 構造函數或 exportObject 方法完成,也可通過相應的 Java.rmi.activation.Activatable 構造函數或 exportObject 方法完成。如果該客戶機套接字工廠在導出遠程對象 時與之相關聯,則客戶機套接字工廠將同遠程對象的引用一起下載到遠程虛擬機 。隨後,RMI 運行時將使用 RMIClIEntSocketFactory.createSocket 方法來建立 從客戶機到遠程對象的連接。

package java.rmi.server; 
public interface RMIClIEntSocketFactory 
{ 
public Java.Net.Socket createSocket(String host, int port) 
throws IOException; 
} 
5.9 RMIFailureHandler 接口 Java.rmi.server.RMIFailureHandler 接口提供一種方法指明服務器套接字創建 失敗時指定 RMI 運行時如何響應(除非對象正在導出)。

package Java.rmi.server; 

public interface RMIFailureHandler 
{ 
public boolean failure(Exception ex); 
} 
當出現了防止 RMI 運行時創建 Java.Net.Socket 的異常時將調用 failure 方法 。如果運行時試圖重試,則該方法返回值為 true;否則將返回 false。 調用該方法前,需要通過調用 RMISocketFactory.setFailureHandler 來注冊失 敗句柄。如果該句柄未設置,則 RMI 運行時等待片刻後嘗試再創建 ServerSock et。 注意,當 ServerSocket 首次導出對象時如果創建 ServerSocket 失敗,就不會 調用 RMIFailureHandler。而當 ServerSocket 接受請求失敗後再創建該 Serve rSocket 時,即調用 RMIFailureHandler。 5.10 LogStream 類 類 LogStream 提供一種記錄錯誤的機制。對系統進行監控的人可能會對這些錯誤 感興趣。該類在內部用於日志服務器調用。


package java.rmi.server; 

public class LogStream extends Java.io.PrintStream 
{ 
public static LogStream log(String name); 
public static synchronized PrintStream getDefaultStream(); 
public static synchronized void setDefaultStream( 
PrintStream newDefault); 
public synchronized OutputStream getOutputStream(); 
public synchronized void setOutputStream(OutputStream out); 
public void write(int b); 
public void write(byte b[], int off, int len); 
public String toString(); 
public static int parseLevel(String s); 
// 日志等級常數 
public static final int SILENT = 0; 
public static final int BRIEF = 10; 
public static final int VERBOSE = 20; 
} 

---------------------------------------------------------------------- ---------- 注意 -JDK1.2 中不鼓勵使用 LogStream 類 ---------------------------------------------------------------------- ---------- 方法 log 返回由給定名稱標識的 LogStream。如果某名稱所對應的日志不存在, 即創建一個使用缺省流的日志。 方法 getDefaultStream 返回用於新日志的當前缺省流。 方法 setDefaultStream 為新日志設置缺省流。 方法 getOutputStream 返回當前日志輸出到的流。 方法 setOutputStream 設置日志的輸出流。 方法 write 的第一種形式將向該流寫一個字節數據。如果不是新起一行,則將把 該字節添加到內部緩沖區。如果是新起一行,則當前緩沖區中的行將按相應的日 志前綴發送到日志的輸出流中。方法 write 的第二種形式將寫字節子數組。 方法 toString 以字符串形式返回日志名。 方法 parseLevel 將日志等級的字符串名轉換為內部整型表示。 5.11 stub 和 skeleton 編譯器 rmic 的 stub 和 skeleton 編譯器用於為特定的遠程對象實現編譯相應的 stub 和 skeleton。該編譯器將由遠程對象類的類全名調用。該類必須在先前已成功 編譯過。 導入類的位置由環境變量 CLASSPATH 或參數 -classpath 指定。 除非指定參數 -d,否則編譯好的類文件將放在當前目錄下。 參數 -keepgenerated (或 -keep)為 stub 和 skeleton 保留生成的 java 源 文件。 也可指定 stub 協議的版本: - -v1.1 創建符合 JDK 1.1 stub 協議版本的 stub/skeleton - -vcompat(JDK 1.2 中為缺省值)創建同時兼容 JDK 1.1 和 1.2 stub 協議 版本的 stub/skeleton - -v1.2 創建僅符合 JDK 1.2 stub 協議版本的 stub(注意,JDK 1.2 stub 協議中並不需要 skeleton) -show 選項為程序顯示一個圖形用戶界面。 大多數 javac 命令行參數均可用(-O 除外)且可與 rmic 一起使用: - -g 生成調試信息 - -depend 反復編譯過期文件 - -nowarn 不生成警告信息 - -verbose 輸出有關編譯器所執行的操作的消息 - -classpath 指定查找輸入源及類文件的位置 - -d 指定放置生成類文件的位置 - -J< runtime flag> 將參數傳給 Java 解釋器
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved