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并且具有一个公共无参数构造函数,则将调用该构造函数以创建提供者实例。如果定义了属性但不满足任何其他条件,则将向尝试使用RMIClassLoader的代码抛出未指定的Error,指示未能获取提供者实例。 - 如果系统类加载器可见的资源名为
META-INF/services/java.rmi.server.RMIClassLoaderSpi,则该资源的内容将被解释为提供者配置文件,并且该文件中指定的第一个类名将用作提供者类名。如果可以通过系统类加载器加载具有该名称的类,并且该类可分配给RMIClassLoaderSpi并且具有一个公共无参数构造函数,则将调用该构造函数以创建提供者实例。如果找到资源但无法按描述实例化提供者,则将向尝试使用RMIClassLoader的代码抛出未指定的Error,指示未能获取提供者实例。 - 否则,提供者实例将是通过调用
getDefaultProviderInstance()方法返回的值。
- 自版本:
- 1.1
- 参见:
-
Method Summary
Modifier and TypeMethodDescriptionstatic 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路径。
-
Method Details
-
loadClass
@Deprecated public static Class<?> loadClass(String name) throws MalformedURLException, ClassNotFoundException Deprecated.replaced byloadClass(String,String)method加载具有指定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)表现相同,其中codebase为null,给定类名。此方法委托给提供者实例的
RMIClassLoaderSpi.loadClass(String,String,ClassLoader)方法,将在给定URL上调用URL.toString()的结果(如果codebase为 null,则为null)作为第一个参数传递,将name作为第二个参数传递,将null作为第三个参数传递。- 参数:
-
codebase- 从中加载类的URL,或null -
name- 要加载的类的名称 - 返回:
-
表示加载类的
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列表(用空格分隔),或null -
name- 要加载的类的名称 - 返回:
-
表示加载类的
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列表(用空格分隔),或null -
name- 要加载的类的名称 -
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列表(以空格分隔),或null -
interfaces- 代理类要实现的接口的名称 -
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作为参数。如果存在安全管理器,将使用
RuntimePermission("getClassLoader")权限调用其checkPermission方法;这可能导致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。默认服务提供程序实例实现如下:
RMIClassLoaderSpigetClassAnnotation方法返回一个表示远程方应使用的代码库URL路径以下载指定类定义的String。返回的字符串格式是由空格分隔的URL路径。返回的代码库字符串取决于指定类的定义类加载器:-
如果类加载器是系统类加载器(参见
ClassLoader.getSystemClassLoader())、用于安装扩展的系统类加载器的父类加载器,或引导类加载器(可能由null表示),则返回java.rmi.server.codebase属性的值(或可能是先前缓存的值),如果未设置该属性,则返回null。 -
否则,如果类加载器是
URLClassLoader的实例,则返回的字符串是通过调用加载器的getURLs方法返回的URL的外部形式的空格分隔列表。如果URLClassLoader是由此提供程序创建的以服务其loadClass或loadProxyClass方法的调用,则不需要权限来获取关联的代码库字符串。如果是任意其他URLClassLoader实例,则如果存在安全管理器,则对于getURLs方法返回的每个URL,将调用其openConnection().getPermission()方法返回的权限;如果其中任何调用引发SecurityException或IOException,则返回java.rmi.server.codebase属性的值(或可能是先前缓存的值),如果未设置该属性,则返回null。 -
最后,如果类加载器不是
URLClassLoader的实例,则返回java.rmi.server.codebase属性的值(或可能是先前缓存的值),如果未设置该属性,则返回null。
对于下面描述的方法的实现,每个调用都有一个关联的
String参数命名为codebase,它是一个由URL路径空格分隔的列表,每个调用都有一个关联的codebase loader,它是使用codebase参数与当前线程的上下文类加载器(参见Thread.getContextClassLoader())来标识的。当存在安全管理器时,此提供程序维护一个由其父类加载器和其代码库URL路径(URL的有序列表)对应的类加载器实例(至少是URLClassLoader的实例)的内部表。如果codebase参数为null,则代码库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.no replacement. As of the Java 2 platform v1.2, RMI no longer uses this method to obtain a class loader's security context.返回给定类加载器的安全上下文。- 参数:
-
loader- 要获取安全上下文的类加载器 - 返回:
- 安全上下文
- 参见:
-