📄 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 格式的主机名字符串,后跟一个整型端口号表示)。对于
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -