RMIClassLoader 包含支持使用 RMI 动态加载类的静态方法。包括从网络位置(一个或多个 URL)加载类和获取远程方应从中加载现有类的位置的方法。这些方法由 RMI 运行时在编组和解组远程方法调用的参数和返回值中包含的类时使用,它们也可以由应用程序直接调用以模仿 RMI 的动态类加载行为。
以下静态方法的实现
loadClass(URL,String)loadClass(String,String)loadClass(String,String,ClassLoader)loadProxyClass(String,String[],ClassLoader)getClassLoader(String)getClassAnnotation(Class)
RMIClassLoaderSpi 的实例提供,这些方法的服务提供者接口。当其中一个方法被调用时,它的行为是委托给服务提供者实例上的相应方法。在每个特定方法的文档中描述了每个方法如何委托给提供者实例的详细信息。
服务提供者实例选择如下:
- 如果系统属性
java.rmi.server.RMIClassLoaderSpi被定义,那么如果它的值等于字符串"default",提供者实例将是调用getDefaultProviderInstance()方法返回的值,对于任何其他值,如果以属性值命名的类可以由系统类加载器加载(请参阅ClassLoader.getSystemClassLoader())并且该类可分配给RMIClassLoaderSpi并且具有公共无参数构造函数,然后将调用该构造函数来创建提供者实例。如果属性已定义但任何其他条件不为真,则未指定的Error将被抛出到尝试使用RMIClassLoader的代码,指示无法获取提供程序实例。 - 如果名为
META-INF/services/java.rmi.server.RMIClassLoaderSpi的资源对系统类加载器可见,则该资源的内容被解释为提供者配置文件,并且该文件中指定的第一个类名用作提供者类名。如果具有该名称的类可以由系统类加载器加载并且该类可分配给RMIClassLoaderSpi并且具有公共无参数构造函数,那么将调用该构造函数来创建提供者实例。如果找到资源但无法按描述实例化提供者,则将向尝试使用RMIClassLoader的代码抛出未指定的Error,指示无法获取提供者实例。 - 否则,提供者实例将是调用
getDefaultProviderInstance()方法返回的值。
- 自从:
- 1.1
- 参见:
-
方法总结
修饰符和类型方法描述static StringgetClassAnnotation(Class<?> cl) 返回注释字符串(表示类定义的位置),RMI 在编组给定类的对象时将使用它来注释类描述符。static ClassLoadergetClassLoader(String codebase) 返回一个类加载器,它从给定的代码库 URL 路径加载类。static RMIClassLoaderSpi返回服务提供者接口RMIClassLoaderSpi的默认提供者的规范实例。static ObjectgetSecurityContext(ClassLoader loader) 已弃用。没有替代品。static Class<?>已弃用。替换为loadClass(String,String)方法static Class<?>从代码库 URL 路径加载类。static Class<?>loadClass(String codebase, String name, ClassLoader defaultLoader) 从代码库 URL 路径加载一个类,可以选择使用提供的加载器。static Class<?>从代码库 URL 加载类。static Class<?>loadProxyClass(String codebase, String[] interfaces, ClassLoader defaultLoader) 加载动态代理类(请参阅Proxy),该类实现一组具有来自代码库 URL 路径的给定名称的接口。
-
方法详情
-
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
public static Class <?> loadClass(URL codebase, String name) throws MalformedURLException , ClassNotFoundException 从代码库 URL 加载类。如果codebase是null,则此方法的行为与loadClass(String,String)相同,带有nullcodebase和给定的类名。此方法委托给提供者实例的
RMIClassLoaderSpi.loadClass(String,String,ClassLoader)方法,传递在给定 URL 上调用URL.toString()的结果(或null如果codebase为空)作为第一个参数,name作为第二个参数,null作为第三个参数。- 参数:
codebase- 从中加载类的 URL,或nullname- 要加载的类的名称- 返回:
-
代表加载类的
Class对象 - 抛出:
MalformedURLException- 如果codebase是null并且用于加载类的特定于提供者的 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 列表(以空格分隔),或nullname- 要加载的类的名称- 返回:
-
代表加载类的
Class对象 - 抛出:
MalformedURLException- 如果codebase是非null并且包含无效的 URL,或者如果codebase是null并且用于加载类的特定于提供者的 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 列表(以空格分隔),或nullname- 要加载的类的名称defaultLoader- 要使用的附加上下文类加载器,或null- 返回:
-
代表加载类的
Class对象 - 抛出:
MalformedURLException- 如果codebase是非null并且包含无效的 URL,或者如果codebase是null并且用于加载类的特定于提供者的 URL 无效ClassNotFoundException- 如果在指定位置找不到该类的定义- 自从:
- 1.4
-
loadProxyClass
public static Class <?> loadProxyClass(String codebase, String [] interfaces, ClassLoader defaultLoader) throws ClassNotFoundException , MalformedURLException 加载动态代理类(请参阅Proxy),该类实现一组具有来自代码库 URL 路径的给定名称的接口。接口将被解析,类似于使用给定的
codebase通过loadClass(String,String)方法加载的类。此方法委托给提供者实例的
RMIClassLoaderSpi.loadProxyClass(String,String[],ClassLoader)方法,传递codebase作为第一个参数,interfaces作为第二个参数,defaultLoader作为第三个参数。- 参数:
codebase- 从中加载类的 URL 列表(以空格分隔),或nullinterfaces- 代理类要实现的接口名称defaultLoader- 要使用的附加上下文类加载器,或null- 返回:
- 实现命名接口的动态代理类
- 抛出:
MalformedURLException- 如果codebase是非null并且包含无效的 URL,或者如果codebase是null并且用于加载类的特定于提供者的 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作为参数传递。如果有安全管理器,它的
checkPermission方法将以RuntimePermission("getClassLoader")权限被调用;这可能会导致SecurityException。此方法的提供者实现还可以执行进一步的安全检查,以验证调用上下文是否有权连接到代码库 URL 路径中的所有 URL。- 参数:
codebase- 返回的类加载器将从中加载类的 URL 列表(以空格分隔),或null- 返回:
- 从给定的代码库 URL 路径加载类的类加载器
- 抛出:
MalformedURLException- 如果codebase是非null并且包含无效的 URL,或者如果codebase是null并且用于标识类加载器的特定于提供者的 URL 无效SecurityException- 如果存在安全管理器并且调用其checkPermission方法失败,或者如果调用者无权连接到代码库 URL 路径中的所有 URL- 自从:
- 1.3
-
getClassAnnotation
返回注释字符串(表示类定义的位置),RMI 在编组给定类的对象时将使用它来注释类描述符。此方法委托给提供者实例的
RMIClassLoaderSpi.getClassAnnotation(Class)方法,将cl作为参数传递。- 参数:
cl- 获取注解的类- 返回:
-
一个字符串,用于在编组时注释给定的类,或
null - 抛出:
NullPointerException- 如果cl是null- 自从:
- 1.2
-
getDefaultProviderInstance
返回服务提供者接口RMIClassLoaderSpi的默认提供者的规范实例。如果未定义系统属性java.rmi.server.RMIClassLoaderSpi,则RMIClassLoader静态方法loadClass(URL,String)loadClass(String,String)loadClass(String,String,ClassLoader)loadProxyClass(String,String[],ClassLoader)getClassLoader(String)getClassAnnotation(Class)
如果有安全管理器,它的
checkPermission方法将以RuntimePermission("setFactory")权限被调用;这可能会导致SecurityException。默认服务提供者实例实现
RMIClassLoaderSpi如下:这
getClassAnnotation方法返回一个String表示远程方应该用来下载指定类的定义的代码库 URL 路径。返回字符串的格式是以空格分隔的 URL 路径。返回的代码库字符串取决于指定类的定义类加载器:如果类加载器是系统类加载器(请参阅
ClassLoader.getSystemClassLoader())、系统类加载器的父级(例如用于已安装扩展的加载器)或引导类加载器(可能由null表示),则java.rmi.server.codebase的值返回属性(或可能是更早的缓存值),如果未设置该属性,则返回null。否则,如果类加载器是
URLClassLoader的实例,则返回的字符串是通过调用加载器的getURLs方法返回的 URL 的外部形式的空格分隔列表。如果URLClassLoader由该提供者创建以服务其loadClass或loadProxyClass方法的调用,则无需权限即可获取关联的代码库字符串。如果它是一个任意的其他URLClassLoader实例,那么如果有一个安全管理器,它的checkPermission方法将为getURLs方法返回的每个 URL 调用一次,并通过在每个 URL 上调用openConnection().getPermission()返回权限;如果这些调用中的任何一个抛出SecurityException或IOException,则返回java.rmi.server.codebase属性的值(或可能是更早的缓存值),或者如果未设置该属性,则返回null。最后,如果类加载器不是
URLClassLoader的实例,则返回java.rmi.server.codebase属性的值(或可能是更早的缓存值),或者如果未设置该属性,则返回null。
对于下面描述的方法的实现,它们都采用名为
codebase的String参数,这是一个以空格分隔的 URL 列表,每个调用都有一个关联的代码库加载器这是使用codebase参数和当前线程的上下文类加载器一起识别的(参见Thread.getContextClassLoader())。当有安全管理器时,此提供程序会维护一个类加载器实例(至少是URLClassLoader的实例)的内部表,该表由一对父类加载器和它们的代码库 URL 路径(一个有序的 URL 列表)作为键控。如果codebase参数是null,则代码库 URL 路径是系统属性java.rmi.server.codebase的值或可能是更早的缓存值。对于作为codebase参数传递给在给定上下文中调用以下方法之一的给定代码库 URL 路径,代码库加载器是表中具有指定代码库 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
已弃用。没有替代品。从 Java 2 平台 v1.2 开始,RMI 不再使用此方法来获取类加载器的安全上下文。返回给定类加载器的安全上下文。- 参数:
loader- 从中获取安全上下文的类加载器- 返回:
- 安全上下文
- 参见:
-