Module java.rmi
Package java.rmi.server

Class RMIClassLoader

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 并且具有一个公共无参数构造函数,则将调用该构造函数以创建提供者实例。如果定义了属性但不满足任何其他条件,则将向尝试使用 RMIClassLoader 的代码抛出未指定的 Error,指示未能获取提供者实例。
  • 如果系统类加载器可见的资源名为 META-INF/services/java.rmi.server.RMIClassLoaderSpi,则该资源的内容将被解释为提供者配置文件,并且该文件中指定的第一个类名将用作提供者类名。如果可以通过系统类加载器加载具有该名称的类,并且该类可分配给 RMIClassLoaderSpi 并且具有一个公共无参数构造函数,则将调用该构造函数以创建提供者实例。如果找到资源但无法按描述实例化提供者,则将向尝试使用 RMIClassLoader 的代码抛出未指定的 Error,指示未能获取提供者实例。
  • 否则,提供者实例将是通过调用 getDefaultProviderInstance() 方法返回的值。
自版本:
1.1
参见:
  • Method Details

    • loadClass

      @Deprecated public static Class<?> loadClass(String name) throws MalformedURLException, ClassNotFoundException
      Deprecated.
      replaced by loadClass(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加载类。如果 codebasenull,则此方法将与 loadClass(String,String) 表现相同,其中 codebasenull,给定类名。

      此方法委托给提供者实例的 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 - 如果 codebasenull 并包含无效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 - 如果 codebasenull 并包含无效URL,或者如果 codebasenull 并且用于加载类的特定于提供者的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,或者如果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静态方法 将使用默认提供程序的规范实例作为服务提供程序实例。

      如果存在安全管理器,则将使用其checkPermission方法来检查是否具有RuntimePermission("setFactory")权限;这可能导致SecurityException

      默认服务提供程序实例实现如下:RMIClassLoaderSpi

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

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

      • 否则,如果类加载器是URLClassLoader的实例,则返回的字符串是通过调用加载器的getURLs方法返回的URL的外部形式的空格分隔列表。如果URLClassLoader是由此提供程序创建的以服务其loadClassloadProxyClass方法的调用,则不需要权限来获取关联的代码库字符串。如果是任意其他URLClassLoader实例,则如果存在安全管理器,则对于getURLs方法返回的每个URL,将调用其openConnection().getPermission()方法返回的权限;如果其中任何调用引发SecurityExceptionIOException,则返回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 public static Object getSecurityContext(ClassLoader loader)
      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 - 要获取安全上下文的类加载器
      返回:
      安全上下文
      参见: