java.rmi.server

接口
异常
java.lang.Object
  继承者 java.rmi.server.RMIClassLoader

public class RMIClassLoader
     
extends Object

RMIClassLoader 包含支持用 RMI 进行动态类加载的静态方法。包含从网络位置(一个或多个 URL)加载类和获取远程方应从其加载现有类的位置的方法。这些方法由 RMI 运行库在编组和解组参数中包含的类时使用,将返回远程方法调用的值,并且还可以由应用程序直接调用,以模仿 RMI 的动态类加载行为。

以下静态方法的实现

由这些方法的服务提供者接口 RMIClassLoaderSpi 的实例提供。当调用这些方法之一时,其行为是向服务提供者实例委托相应的方法。有关每个方法如何委托给提供者实例的详细信息,在各自特定方法的文档中进行了描述。

服务提供者实例按以下方式选择:

  • 如果定义了系统属性 java.rmi.server.RMIClassLoaderSpi,则其值等于字符串 "default" 时,提供者实例将是调用 getDefaultProviderInstance() 方法返回的值;对于任何其他值,如果可以通过系统类加载器(请参阅 ClassLoader.getSystemClassLoader())加载用属性值命名的类,并且该类可以分配给 RMIClassLoaderSpi 且具有一个公共无参数的构造方法,则调用构造方法来创建提供者实例。如果定义了属性,但这些条件的所有其他项都不为 true,则向尝试使用 RMIClassLoader 的代码抛出一个不确定的 Error,以指示获取提供者实例失败。
  • 如果名为 META-INF/services/java.rmi.server.RMIClassLoaderSpi 的资源对于系统类加载器来说是可见的,则将该资源的内容解释为提供者配置文件,并将在该文件中指定的第一个类名称用作提供者类名称。如果可以通过系统类加载器加载具有该名称的类,并且该类可分配给 RMIClassLoaderSpi 且有一个公共无参数的构造方法,则调用该构造方法以创建提供者实例。如果找到了资源,但无法按描述的方式实例化提供者,则向尝试使用 RMIClassLoader 的代码抛出一个不确定的 Error,以指示未成功获得提供者实例。
  • 否则,提供者实例将是通过调用 getDefaultProviderInstance() 方法返回的值。

从以下版本开始:
JDK1.1
另请参见:
RMIClassLoaderSpi

方法摘要
static String getClassAnnotation(Class<?> cl)
          返回表示类定义位置的注释字符串,RMI 将在编组给定类的对象时用其注释类描述符。
static ClassLoader getClassLoader(String codebase)
          返回从给定的基本代码 URL 路径加载类的类加载器。
static RMIClassLoaderSpi getDefaultProviderInstance()
          返回服务提供者接口 RMIClassLoaderSpi 的默认提供者的规范化实例。
static Object getSecurityContext(ClassLoader loader)
          已过时。 无替换版本。从 Java 2 平台 v1.2 开始,RMI 不再使用此方法来获取类加载器的安全上下文。
static Class<?> loadClass(String name)
          已过时。 loadClass(String,String) 方法取代
static Class<?> loadClass(String codebase, String name)
          从基本代码 URL 路径加载类。
static Class<?> loadClass(String codebase, String name, ClassLoader defaultLoader)
          有选择地使用提供的加载器从基本代码 URL 路径加载类。
static Class<?> loadClass(URL codebase, String name)
          从基本代码 URL 加载类。
static Class<?> loadProxyClass(String codebase, String[] interfaces, ClassLoader defaultLoader)
          从基本代码 URL 路径加载一个实现一组具有给定名称的接口的动态代理类(请参阅 Proxy)。
 
从类 java.lang.Object 继承的方法
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

方法详细信息

loadClass

@Deprecated
public static Class<?> loadClass(String name)
                          throws MalformedURLException,
                                 ClassNotFoundException
已过时。  loadClass(String,String) 方法取代

加载具有指定 name 的类。

此方法委托给 loadClass(String,String),将 null 作为第一个参数,将 name 作为第二个参数进行传递。

参数:
name - 要加载的类的名称
返回:
表示加载的类的 Class 对象
抛出:
MalformedURLException - 如果用于加载类的特定于提供者的 URL 无效
ClassNotFoundException - 如果在基本代码基无法找到该类的定义
另请参见:
loadClass(String,String)

loadClass

public static Class<?> loadClass(URL codebase,
                                 String name)
                          throws MalformedURLException,
                                 ClassNotFoundException
从基本代码 URL 加载类。 如果 codebasenull,则此方法将与具有 nullcodebase 和给定类名的 loadClass(String,String) 行为相同。

此方法委托给提供者实例的 RMIClassLoaderSpi.loadClass(String,String,ClassLoader) 方法,将在给定 URL 上调用 URL.toString() 的结果(或者如果 codebase 为 null,则为 null)作为第一个参数、name 为第二个参数和 null 为第三个参数进行传递。

参数:
codebase - 要从其加载类的 URL,或 null
name - 要加载的类的名称
返回:
表示加载的类的 Class 对象
抛出:
MalformedURLException - 如果 codebasenull 且用于加载类的特定于提供者的 URL 无效
ClassNotFoundException - 如果在指定 URL 无法找到该类的定义

loadClass

public static Class<?> loadClass(String codebase,
                                 String name)
                          throws MalformedURLException,
                                 ClassNotFoundException
从基本代码 URL 路径加载类。

此方法委托给提供者实例的 RMIClassLoaderSpi.loadClass(String,String,ClassLoader) 方法,将 codebase 作为第一个参数、name 为第二个参数和 null 为第三个参数进行传递。

参数:
codebase - 要从其加载类的 URL 的列表(由空格分隔),或者为 null
name - 要加载的类的名称
返回:
表示加载的类的 Class 对象
抛出:
MalformedURLException - 如果 codebase 为非 null 且包含一个无效 URL,或者如果 codebasenull 且用于加载类的特定于提供者的 URL 无效。
ClassNotFoundException - 如果在指定位置无法找到该类的定义
从以下版本开始:
1.2

loadClass

public static Class<?> loadClass(String codebase,
                                 String name,
                                 ClassLoader defaultLoader)
                          throws MalformedURLException,
                                 ClassNotFoundException
有选择地使用提供的加载器从基本代码 URL 路径加载类。当调用方想让要考虑的其他上下文类加载器(如堆栈上的调用方加载器)可用于提供者实现时应该使用此方法。通常,提供者实现将试图先使用给定的 defaultLoader(如果指定)解析指定的类,然后才试图从代码基 URL 路径解析该类。

此方法委托给提供者实例的 RMIClassLoaderSpi.loadClass(String,String,ClassLoader) 方法,将 codebase 作为第一个参数、name 为第二个参数和 defaultLoader 为第三个参数进行传递。

参数:
codebase - 要从其加载类的 URL 的列表(由空格分隔),或者为 null
name - 要加载的类的名称
defaultLoader - 要使用的其他上下文类加载器,或 null
返回:
表示加载的类的 Class 对象
抛出:
MalformedURLException - 如果 codebase 为非 null 且包含一个无效 URL,或者如果 codebasenull 且用于加载类的特定于提供者的 URL 无效。
ClassNotFoundException - 如果在指定位置无法找到该类的定义
从以下版本开始:
1.4

loadProxyClass

public static Class<?> loadProxyClass(String codebase,
                                      String[] interfaces,
                                      ClassLoader defaultLoader)
                               throws ClassNotFoundException,
                                      MalformedURLException
从基本代码 URL 路径加载一个实现一组具有给定名称的接口的动态代理类(请参阅 Proxy)。

将解析的接口类似于通过使用给定 codebaseloadClass(String,String) 方法加载的类。

此方法委托给提供者实例的 RMIClassLoaderSpi.loadProxyClass(String,String[],ClassLoader) 方法,将 codebase 作为第一个参数、interfaces 为第二个参数和 defaultLoader 为第三个参数进行传递。

参数:
codebase - 要从其加载类的 URL 列表(由空格分隔),或 null
interfaces - 要实现的代理类的接口名称
defaultLoader - 要使用的其他上下文类加载器,或 null
返回:
实现指定接口的动态代理类
抛出:
MalformedURLException - 如果 codebase 为非 null 且包含一个无效 URL,或者如果 codebasenull 且用于加载类的特定于提供者的 URL 无效。
ClassNotFoundException - 如果在指定位置无法找到某个指定接口的定义,或者如果动态代理类的创建失败(例如,如果 Proxy.getProxyClass(ClassLoader,Class[]) 抛出给定接口列表的 IllegalArgumentException
从以下版本开始:
1.4

getClassLoader

public static ClassLoader getClassLoader(String codebase)
                                  throws MalformedURLException,
                                         SecurityException
返回从给定的基本代码 URL 路径加载类的类加载器。

返回的类加载器是 loadClass(String,String) 方法将用来加载相同 codebase 参数的类的类加载器。

此方法委托给提供者实例的 RMIClassLoaderSpi.getClassLoader(String) 方法,将 codebase 作为第一个参数进行传递。

如果存在安全管理器,则使用 RuntimePermission("getClassLoader") 权限调用其 checkPermission 方法;这会导致 SecurityException。此方法的提供者实现还可以执行进一步的安全检查,以验证调用上下文是否具有连接到代码基 URL 路径中的所有 URL 的权限。

参数:
codebase - 返回的类加载器将从其加载类的 URL 列表(由空格分隔),或 null
返回:
从给定代码基 URL 路径加载类的类加载器
抛出:
MalformedURLException - 如果 codebase 为非 null 且包含一个无效 URL,或者如果 codebasenull 且用于标识类加载器的特定于提供方的 URL 无效
SecurityException - 如果存在安全管理器且其 checkPermission 方法的调用失败,或者如果调用方没有连接到代码基 URL 路径中所有 URL 的权限
从以下版本开始:
1.3

getClassAnnotation

public static String getClassAnnotation(Class<?> cl)
返回表示类定义位置的注释字符串,RMI 将在编组给定类的对象时用其注释类描述符。

此方法委托给提供者实例的 RMIClassLoaderSpi.getClassAnnotation(Class) 方法,将 cl 作为第一个参数进行传递。

参数:
cl - 要获得其注释的类
返回:
在编组时用于注释给定类的字符串,或 null
抛出:
NullPointerException - 如果 clnull
从以下版本开始:
1.2

getDefaultProviderInstance

public static RMIClassLoaderSpi getDefaultProviderInstance()
返回服务提供者接口 RMIClassLoaderSpi 的默认提供者的规范化实例。如果未定义系统属性 java.rmi.server.RMIClassLoaderSpi,则 RMIClassLoader 静态方法 将把默认提供者的规范化实例用作服务提供者实例。

如果存在安全管理器,则使用 RuntimePermission("setFactory") 权限调用其 checkPermission 方法;这会导致 SecurityException

默认服务提供者实例按以下方式实现 RMIClassLoaderSpi

getClassAnnotation 方法返回一个表示基本代码 URL 路径的 String,远程方应使用该路径下载指定类的定义。返回的字符串的格式是一个由空格分隔的 URL 路径。 返回的基本代码字符串取决于指定类的定义类加载器:

  • 如果类加载器是系统类加载器(请参阅 ClassLoader.getSystemClassLoader())、系统类加载器的父级(如,用于安装扩展的加载器) 或引导类加载器(可以用 null 表示),则返回 java.rmi.server.codebase 属性的值(或可能是一个原先的缓存值);如果未设置该属性,则返回 null

  • 否则,如果类加载器是 URLClassLoader 的实例,则返回的字符串是一个 URL 的外部形式的由空格分隔的列表,该 URL 通过调用加载器 getURLs 方法返回。如果 URLClassLoader 由此提供者创建,用于调用其 loadClassloadProxyClass 方法,则不需要任何权限即可获取关联的基本代码字符串。如果它是其他任意一个 URLClassLoader 实例,则如果存在安全管理器,则对于 getURLs 方法返回的每个 URL 都要调用一次其 checkPermission 方法(所用的权限为对每个 URL 调用 openConnection().getPermission() 返回的权限);如果这些调用的任何一个抛出 SecurityExceptionIOException,则返回 java.rmi.server.codebase 属性的值(或可能是原先的缓存值);如果未设置该属性,则返回 null

  • 最后,如果类加载器不是 URLClassLoader 的实例,则返回 java.rmi.server.codebase 属性的值(或可能是原先的缓存值);如果未设置该属性,则返回 null

对于下面描述的方法的实现,这些实现都采用作为由空格分隔的 URL 列表的名为 codebaseString 参数,每个调用都有一个关联的基本代码加载器,它通过将 codebase 与当前线程的上下文类加载器一起使用进行标识(请参阅 Thread.getContextClassLoader())。存在安全管理器时,此提供者将维护类加载器实例(至少是 URLClassLoader 的实例)的内部表,这些内部表通过其父类加载器及其基本代码 URL 路径(排序的 URL 列表)键入。如果 codebasenull,则基本代码 URL 路径是系统属性 java.rmi.server.codebase 的值,或可能是原先的缓存值。对于给定的基本代码 URL 路径(该路径作为 codebase 参数传递到下面给定上下文中的方法之一的调用),基本代码加载器位于具有指定基本代码 URL 路径的表中且当前线程的上下文类加载器是其父级的加载器。如果不存在这样的加载器,则创建一个这样的加载器并将其添加到表中。该表不维护对其包含的加载器的强引用,以便于允许它们及其定义类在不可另外到达时被垃圾回收。为了防止不受信任的任意代码被隐式加载到不带安全管理器的虚拟机中,如果未设置安全管理器,则基本代码加载器就是当前线程的上下文类加载器(提供的基本代码 URL 路径被忽略,所以禁止了远程类加载)。

getClassLoader 方法返回指定基本代码 URL 路径的基本代码加载器。如果存在安全管理器,则如果该调用上下文没有连接到基本代码 URL 路径上的所有 URL 的权限,则抛出 SecurityException

loadClass 方法尝试按以下方式加载具有指定名称的类:

如果 defaultLoader 为非 null,则它首先尝试使用 defaultLoader 加载具有指定 name 的类,比如通过评估
     Class.forName(name, false, defaultLoader)
 
如果从 defaultLoader 成功加载了类,则返回该类。如果抛出 ClassNotFoundException 之外的异常,则该异常被抛给调用方。

其次,loadClass 方法尝试使用指定基本代码 URL 路径的基本代码加载器加载具有指定 name 的类。如果存在安全管理器,则该调用上下文必须具有连接到基本代码 URL 上的所有 URL 的权限;否则,将使用当前线程的上下文类加载器,而不是基本代码加载器。

loadProxyClass 方法尝试按以下方式返回具有指定接口的动态代理类:

如果 defaultLoader 参数为非 null 且可以通过该加载器解析所有指定接口,则,

  • 如果所有解析的接口都为 public,则它首先尝试获得在基本代码加载器中定义的解析接口的动态代理类(使用 Proxy.getProxyClass);如果该尝试抛出一个 IllegalArgumentException,则它尝试获得在 defaultLoader 中定义的解析接口的动态代理类。如果两个尝试都抛出 IllegalArgumentException,则此方法将抛出 ClassNotFoundException。如果抛出任何其他异常,则该异常将被抛给调用方。
  • 如果在同一类加载器中定义所有非 public 解析接口,则其尝试获得在该加载器中定义的解析接口的动态代理类。
  • 否则,抛出 LinkageError(因为实现所有指定接口的类无法在任何加载器中定义)。

否则,如果所有指定的接口可通过基本代码加载器解析,则,

  • 如果所有解析接口都为 public,则它尝试获得基本代码中解析接口的动态代理类。如果该尝试抛出 IllegalArgumentException,则此方法抛出一个 ClassNotFoundException
  • 如果在同一类加载器中定义所有非 public 解析接口,则它尝试获得在该加载器中定义的解析接口的动态代理类。
  • 否则,抛出 LinkageError(因为实现所有指定接口的类无法在任何加载器中定义)。

否则,将为每个无法解析的指定接口抛出 ClassNotFoundException

返回:
默认服务提供者的规范化实例
抛出:
SecurityException - 如果存在安全管理器,且其 checkPermission 方法的调用将失败
从以下版本开始:
1.4

getSecurityContext

@Deprecated
public static Object getSecurityContext(ClassLoader loader)
已过时。  无替换版本。从 Java 2 平台 v1.2 开始,RMI 不再使用此方法来获取类加载器的安全上下文。

返回给定类加载器的安全上下文。

参数:
loader - 从其获取安全上下文的类加载器
返回:
安全上下文
另请参见:
SecurityManager.getSecurityContext()