第 8 章
本章包含 rmic stub 编译器生成的 stub 和 skleton 所用的接口和类。
主题:
RemoteStub 类
RemoteCall 接口
RemoteRef 接口
ServerRef 接口
Skeleton 接口
Operation 类
8.1 RemoteStub 类
java.rmi.server.RemoteStub 类是远程对象 stub 的通用超类。stub 对象是一
种代理,它支持的远程接口集与远程对象的实际实现所定义的完全相同。
package java.rmi.server;
public abstract class RemoteStub extends java.rmi.RemoteObject
{
protected RemoteStub();
protected RemoteStub(RemoteRef ref);
protected static void setRef(RemoteStub stub, RemoteRef ref);
}
RemoteStub 的第一个构造函数将创建带有空远程引用的 stub。第二个构造函数
将创建带有给定远程引用 ref 的 stub。
JDK1.2 中不鼓励使用(且不支持)setRef 方法。
8.1.1 远程对象与 stub 类的类型等价性
客户机可与 stub(代理)对象进行交互,该 stub 的远程接口集与远程对象类所
定义的完全相同。由于 stub 类是由实现一个或多个远程接口的实现类精华所生
成的,因此 stub 类不包括类层次(组成对象的类型图)的非远程部分。例如,
如果 C 扩展 B 而 B 扩展 A,但只有 B 实现远程接口,则 stub 将由 B 生成,
而非 C。
由于 stub 实现与远程对象类相同的远程接口集,因此从 Java 系统的角度看,
stub 拥有与服务器对象类型图的远程部分相同的类型。这样,客户机即可利用内
置 Java 操作来检查远程对象的类型,同时也可从一个远程接口向另一远程接口
进行强制类型转换。
stub 是用 rmic 编译器生成的。
8.1.2 声明为终态的对象方法的语义
以下方法在 java.lang.Object 类中被声明为终态 final,因此不能被任意实现
所覆盖:
getClass
notify
notifyAll
wait
getClass 的缺省实现适用于所有 Java 对象(本地或远程);对于远程对象,该
方法不需要专门的实现。getClass 方法在远程 stub 上使用时,它报告由 rmic
生成的 stub 对象的确切类型。注意,stub 类型仅反映远程对象实现的远程接
口,而非本地接口。
java.lang.Object 的 wait 和 notify 方法将处理 Java 语言线程模型上下文中
的等待和通知。虽然对远程 stub 使用这些方法不会违反 Java 线程模型,但这
些方法的语义将与用于本地 Java 对象时的语义不同。尤其,使用这些方法时所
操作的将是远程对象的客户机本地引用 (stub),而不是远程站点的实际对象。
8.2 RemoteCall 接口
RemoteCall 是远程对象的 stub 和 skeleton 所用的抽象接口,用来执行对远程
对象的调用。
----------------------------------------------------------------------
----------
注意 - JDK 1.2 中不鼓励使用 RemoteCall 接口。JDK 1.2 stub 协议也已不再
使用此接口。现在,stub 在 JDK 1.2 中使用新的 invoke 方法,该方法不需要
将 RemoteCall 作为参数。
----------------------------------------------------------------------
----------
package java.rmi.server;
import java.io.*;
public interface RemoteCall
{
ObjectOutput getOutputStream() throws IOException;
void releaseOutputStream() throws IOException;
ObjectInput getInputStream() throws IOException;
void releaseInputStream() throws IOException;
ObjectOutput getResultStream(boolean success)
throws IOException, StreamCorruptedException;
void executeCall() throws Exception;
void done() throws IOException;
}
方法 getOutputStream 返回输出流。stub 将把参数编组到其中,或者 skeleton
将把结果编组到其中。
方法 releaseOutputStream 释放输出流。在某些传输中,这将导致释放流。
方法 getInputStream 返回 InputStream。stub 从中解编结果,或者 skeleton
从中解编参数。
方法 releaseInputStream 释放输入流。这将允许某些传输提前释放连接的输入
端。
方法 getResultStream 返回输出流(写完与调用成功有关的标题信息后)。每次
远程调用将只能获得一次结果流。如果 success 为真,则要编组的结果属于正常
返回;否则结果为异常。如果已获得该远程调用的结果流,则抛出
StreamCorruptedException。
方法 executeCall 尽其所能执行调用。
方法 done 允许完成远程调用后进行清除。
.3 RemoteRef 接口
接口 RemoteRef 表示远程对象的句柄。每个 stub 均包含 RemoteRef 的一个实
例,其中包含引用的具体表示。该远程引用将用来在其代表的远程对象上执行远
程调用。
package java.rmi.server;
public interface RemoteRef extends java.io.Externalizable
{
Object invoke(Remote obj,
java.lang.reflect.Method method,
Object[] params,
long opnum)
throws Exception;
RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum, long hash)
throws RemoteException;
void invoke(RemoteCall call) throws Exception;
void done(RemoteCall call) throws RemoteException;
String getRefClass(java.io.ObjectOutput out);
int remoteHashCode();
boolean remoteEquals(RemoteRef obj);
String remoteToString();
}
第一个 invoke 方法将方法调用代理给 stub (obj) 的远程引用,并允许引用负
责建立对远程主机的连接,将 method 和参数 params 的一些表示进行编组,然
后使用方法调用与远程主机进行通讯。该方法将返回驻留在远程主机上的远程对
象的方法调用结果,或者在调用失败时抛出 RemoteException,而在远程调用抛
出异常时则抛出应用程序级异常。注意,操作号 opnum 表示一散列方法签名,可
以用来对要传输的方法进行编码。
opnum 的方法散列是一个 64 位(长)整数,是根据美国国家标准技术局 (NIST
) 的安全散列算法 (SHA-1),用字节流消息摘要的前两个 32 位值计算而来的。
字节流包含由远程方法名后跟其方法描述符组成的字符串的 UTF 编码(有关方法
描述符的说明,参见 Java 虚拟机规范的第 4.3.3 节)。散列值将从 SHA-1 散
列的第一个和第二个 32 位值得到。
long hash = sha[1] << 32 + sha[0]
----------------------------------------------------------------------
----------
注意 - JDK 1.2 中不鼓励使用 newCall、invoke 和 done 方法。rmic 用 JDK
1.2 stub 协议版本生成的 stub 不再使用这些方法。由 newCall、invoke 和 d
one 组成的调用序列已被新的 invoke 方法所替换,该新方法将 Method 对象作
为一个参数。
----------------------------------------------------------------------
----------
方法 newCall 将为远程对象 obj 上的新远程方法调用创建相应的调用对象。操
作数组 op 包含远程对象上的可用操作。操作号 opnum 是对操作数组的索引,它
指定该远程调用的特定操作。 传递操作数组和索引可使 stub 生成器能分派操作
索引并进行解释。远程引用可能需要操作说明以在调用中进行编码。
方法 invoke 负责执行远程调用。invoke 将产生能顺利通过而不被 stub 捕获的
“用户”异常。如果在远程调用过程中产生异常,则 invoke 应注意在产生“用
户异常”或 RemoteException 之前清除连接。
方法 done 允许远程引用清除(或重新使用)连接。只有当 invoke 调用已成功
地(非异常)返回 stub 时,才应调用 done。
方法 getRefClass 返回将被序列化到流 out 上的引用类型的非包限定的类全名
。
方法 remoteHashCode 返回远程对象的散列码。两个引用相同远程对象的远程对
象 stub 将有相同的散列码(以支持在散列表中将远程对象作为键值)。Remote
Object 将把对其 hashCode 方法的调用转发给远程引用的 remoteHashCode 方法
。
方法 remoteEquals 比较两个远程对象的等价性。如果两个远程对象引用相同的
远程对象,即认为它们等价。例如,如果两个 stub 引用相同的远程对象,则认
为它们等价。 RemoteObject 将把对其 equals 方法的调用转发给远程引用的 r
emoteEquals 方法。
方法 remoteToString 返回表示该远程对象的引用的 String。
8.4 ServerRef 接口
接口 ServerRef 表示远程对象实现的服务器端句柄。
package java.rmi.server;
public interface ServerRef extends RemoteRef {
RemoteStub exportObject(java.rmi.Remote obj, Object data)
throws java.rmi.RemoteException;
String getClientHost() throws ServerNotActiveException;
}
方法 exportObject 将为所提供的 Remote 对象实现 obj 查找或创建客户机 st
ub 对象。参数 data 包含导出对象所需的信息(如端口号)。
方法 getClientHost 返回当前客户机的主机名。当它被当前正在处理远程对象调
用的线程调用时,将返回执行此调用的客户机主机名。如果当前某一远程方法调
用未处于服务状态,则调用 ServerNotActiveException。
8.5 Skeleton 接口
接口 Skeleton 仅能由 rmic 编译器所生成 skeleton 的实现。远程对象的 ske
leton 是服务器端的实体,它将为实际远程对象实现分配调用。
----------------------------------------------------------------------
----------
注意 - JDK1.2 中不鼓励使用 Skeleton 接口。每个由 rmic stub 编译器生成的
1.1(以及在 1.2 中由缺省 rmic -vcompat 生成的兼容 1.1 的 skeleton)sk
eleton 类均实现该接口。JDK1.2 兼容版本中分配远程方法调用将不再需要 ske
leton。要生成兼容 JDK1.2 或更高版本的 stub,请使用带有选项 -v1.2 的命令
rmic。
----------------------------------------------------------------------
----------
package java.rmi.server;
public interface Skeleton
{
void dispatch(Remote obj, RemoteCall call, int opnum, long hash)
throws Exception;
Operation[] getOperations();
}
dispatch 方法将解编 call 对象中获得的输入流中的参数,调用实际远程对象实
现 obj 上的方法(由操作号 opnum 表示),然后将返回值进行编组。如果在调
用过程中发生异常,则抛出异常。
getOperations 方法返回包含远程对象方法的操作描述符的数组。
8.6 Operation 类
类 Operation 包含对远程对象 Java 方法的说明。
----------------------------------------------------------------------
----------
注意 - JDK 1.2 中不鼓励使用 Operation 接口。JDK 1.2 stub 协议不再使用原
有的、以 Operation 作为参数的 RemoteRef.invoke 方法。stub 在 JDK 1.2 中
使用了新的 invoke 方法,它不再需要将 Operation 作为参数。
----------------------------------------------------------------------
----------
package java.rmi.server;
public class Operation
{
public Operation(String op);
public String getOperation();
public String toString();
}
构造 Operation 对象时通常带有方法签名。
方法 getOperation 返回操作描述符的内容(其初始化时使用的值)。
方法 toString 也返回操作描述符的字符串表示(通常为方法签名)。