模块 java.rmi

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

    • 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 加载类。如果 codebasenull ,则此方法的行为与 loadClass(String,String) 相同,带有 null codebase 和给定的类名。

      此方法委托给提供者实例的 RMIClassLoaderSpi.loadClass(String,String,ClassLoader) 方法,传递在给定 URL 上调用 URL.toString() 的结果(或 null 如果 codebase 为空)作为第一个参数,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
      加载动态代理类(请参阅 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 作为参数传递。

      如果有安全管理器,它的checkPermission方法将以RuntimePermission("getClassLoader")权限被调用;这可能会导致 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 方法返回一个 String 表示远程方应该用来下载指定类的定义的代码库 URL 路径。返回字符串的格式是以空格分隔的 URL 路径。返回的代码库字符串取决于指定类的定义类加载器:

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

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

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

      对于下面描述的方法的实现,它们都采用名为 codebaseString 参数,这是一个以空格分隔的 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

      @Deprecated public static Object  getSecurityContext(ClassLoader  loader)
      已弃用。
      没有替代品。从 Java 2 平台 v1.2 开始,RMI 不再使用此方法来获取类加载器的安全上下文。
      返回给定类加载器的安全上下文。
      参数:
      loader - 从中获取安全上下文的类加载器
      返回:
      安全上下文
      参见: