Module java.base
Package java.lang

Class ModuleLayer

java.lang.Object
java.lang.ModuleLayer

public final class ModuleLayer extends Object
Java虚拟机中的模块层。

Configuration的模块图和将每个模块映射到ClassLoader的函数创建一个层。创建一个层会告知Java虚拟机可以从模块中加载哪些类,以便Java虚拟机知道每个类属于哪个模块。

创建一个层会为配置中的每个ResolvedModule创建一个Module对象。对于每个已解析模块,如果模块reads,则Modulereads相应的运行时Module,该模块可以位于同一层或parent层中。

defineModulesWithOneLoaderdefineModulesWithManyLoaders方法提供了方便的方式来创建一个模块层,其中所有模块都映射到单个类加载器,或者每个模块映射到自己的类加载器。 defineModules方法用于更高级的情况,其中模块通过指定给方法的函数映射到自定义类加载器。每个方法都有实例和静态变体。实例方法创建一个以接收者为父层的层。静态方法用于更高级的情况,其中可能有多个父层或需要一个Controller来控制层中的模块。

Java虚拟机至少有一个非空层,即boot层,在启动Java虚拟机时创建。boot层包含模块java.base,是Java虚拟机中唯一具有名为"java.base"的模块的层。boot层中的模块映射到引导类加载器和其他内置于Java虚拟机中的类加载器。在创建额外的层时,boot层通常会成为parent

层中的每个Module都是这样创建的,以便它exportsopens由其ModuleDescriptor描述的包。在创建层时,限定导出(将包导出到一组目标模块而不是所有模块)如下实现:

  • 如果模块X将包导出到Y,并且如果运行时Module X读取Module Y,则该包将导出到Module Y(可能位于与X相同的层或父层中)。
  • 如果模块X将包导出到Y,并且如果运行时Module X不读取Y,则目标Y将被定位,就好像通过调用findModule在层或其父层中找到模块。如果找到Y,则将该包导出到找到的Y的实例。如果未找到Y,则将忽略限定导出。

限定开放的处理方式与限定导出相同。

与创建Configuration时一样,创建层时会对automatic模块进行特殊处理。自动模块在Java虚拟机中作为读取Java虚拟机中的每个未命名ModuleModule创建。

除非另有说明,在此类中的方法中将null参数传递会导致抛出NullPointerException

示例

此示例通过使用boot层的配置解析名为"myapp"的模块来创建一个配置。然后使用此配置中的模块创建一个新层。所有模块都定义为相同的类加载器。

    ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
    ModuleLayer parent = ModuleLayer.boot();
    Configuration cf = parent.configuration()
                             .resolve(finder, ModuleFinder.of(), Set.of("myapp"));
    ClassLoader scl = ClassLoader.getSystemClassLoader();
    ModuleLayer layer = parent.defineModulesWithOneLoader(cf, scl);
    Class<?> c = layer.findLoader("myapp").loadClass("app.Main");
自JDK版本:
9
参见:
  • Method Details

    • defineModulesWithOneLoader

      public ModuleLayer defineModulesWithOneLoader(Configuration cf, ClassLoader parentLoader)
      通过将给定的Configuration中的模块定义到Java虚拟机中,创建一个新的模块层,其父层为此层。此方法创建一个类加载器,并将所有模块定义为该类加载器。每个类加载器的parent是给定的父类加载器。当以此层为父层调用静态defineModulesWithOneLoader方法时,此方法的工作方式与其指定的完全相同。换句话说,如果此层为thisLayer,则此方法等效于调用:
       
           ModuleLayer.defineModulesWithOneLoader(cf, List.of(thisLayer), parentLoader).layer();
       
      参数:
      cf - 层的配置
      parentLoader - 由此方法创建的类加载器的父类加载器;对于引导类加载器,可能为null
      返回:
      新创建的层
      抛出:
      IllegalArgumentException - 如果给定的配置具有多个父级或配置的父级不是此层的配置
      LayerInstantiationException - 如果由静态defineModulesWithOneLoader方法指定的任何原因导致无法创建层
      SecurityException - 如果安全管理器拒绝RuntimePermission("createClassLoader")RuntimePermission("getClassLoader")
      参见:
    • defineModulesWithManyLoaders

      public ModuleLayer defineModulesWithManyLoaders(Configuration cf, ClassLoader parentLoader)
      通过将给定的Configuration中的模块定义到Java虚拟机中,创建一个新的模块层,其父层为此层。每个模块都定义为由此方法创建的自己的ClassLoader。每个类加载器的parent是给定的父类加载器。当以此层为父层调用静态defineModulesWithManyLoaders方法时,此方法的工作方式与其指定的完全相同。换句话说,如果此层为thisLayer,则此方法等效于调用:
       
           ModuleLayer.defineModulesWithManyLoaders(cf, List.of(thisLayer), parentLoader).layer();
       
      参数:
      cf - 层的配置
      parentLoader - 由此方法创建的每个类加载器的父类加载器;对于引导类加载器,可以为null
      返回:
      新创建的层
      抛出:
      IllegalArgumentException - 如果给定的配置有多个父级或配置的父级不是此层的配置
      LayerInstantiationException - 如果由于静态defineModulesWithManyLoaders方法指定的任何原因而无法创建层
      SecurityException - 如果安全管理器拒绝RuntimePermission("createClassLoader")RuntimePermission("getClassLoader")
      参见:
    • defineModules

      public ModuleLayer defineModules(Configuration cf, Function<String,ClassLoader> clf)
      创建一个新的模块层,以此层作为其父层,通过定义给定Configuration中的模块到Java虚拟机。每个模块都通过给定的函数按名称映射到其类加载器。当以此层为父级调用时,此方法的工作方式与静态defineModules方法指定的完全相同。换句话说,如果此层为thisLayer,则此方法等效于调用:
       
           ModuleLayer.defineModules(cf, List.of(thisLayer), clf).layer();
       
      参数:
      cf - 层的配置
      clf - 将模块名称映射到类加载器的函数
      返回:
      新创建的层
      抛出:
      IllegalArgumentException - 如果给定的配置有多个父级或配置的父级不是此层的配置
      LayerInstantiationException - 如果由于静态defineModules方法指定的任何原因而无法创建层
      SecurityException - 如果安全管理器拒绝RuntimePermission("getClassLoader")
    • defineModulesWithOneLoader

      public static ModuleLayer.Controller defineModulesWithOneLoader(Configuration cf, List<ModuleLayer> parentLayers, ClassLoader parentLoader)
      通过将给定Configuration中的模块定义到Java虚拟机来创建一个新的模块层。此方法创建一个类加载器并将所有模块定义到该类加载器。

      此方法创建的类加载器在从模块加载类时实现直接委托。如果调用loadClass方法来加载一个类,则它使用类的包名将其映射到一个模块。这可能是此层中的一个模块,因此定义为同一个类加载器。它可能是父层中的一个模块中的包,该包被导出到此层中的一个或多个模块。类加载器委托给模块的类加载器,如果该类加载器找不到,则抛出ClassNotFoundException。当调用loadClass来加载不映射到模块的类时,它会委托给父类加载器。

      此方法创建的类加载器在搜索父类加载器之前在层中的所有模块中定位资源(getResourcegetResources和其他资源方法)。

      尝试使用所有模块定义到同一个类加载器创建层可能会因以下原因而失败:

      • 重叠的包:配置中的两个或多个模块具有相同的包。

      • 分割委托:结果类加载器需要委托给多个类加载器才能加载特定包中的类。

      此外,如果配置包含名为"java.base"的模块,或者模块包含名为"java"或以"java."开头的包,则无法创建层。

      如果存在安全管理器,则此方法创建的类加载器将以受调用此方法的调用上下文限制的权限加载类和资源。

      参数:
      cf - 层的配置
      parentLayers - 搜索顺序中的父层列表
      parentLoader - 由此方法创建的类加载器的父类加载器;对于引导类加载器,可以为null
      返回:
      控制新创建的层的控制器
      抛出:
      IllegalArgumentException - 如果给定配置的父级与父层的配置(包括顺序)不匹配
      LayerInstantiationException - 如果由于上述任何原因所有模块无法定义到同一个类加载器
      SecurityException - 如果安全管理器拒绝RuntimePermission("createClassLoader")RuntimePermission("getClassLoader")
      参见:
    • defineModulesWithManyLoaders

      public static ModuleLayer.Controller defineModulesWithManyLoaders(Configuration cf, List<ModuleLayer> parentLayers, ClassLoader parentLoader)
      通过将给定Configuration中的模块定义到Java虚拟机来创建一个新的模块层。每个模块都定义到由此方法创建的自己的ClassLoader。每个类加载器的parent是给定的父类加载器。

      此方法创建的类加载器在从模块加载类时实现直接委托。如果调用loadClass方法来加载一个类,则它使用类的包名将其映射到一个模块。该包可能在定义为类加载器的模块中。该包可能由此层中的另一个模块导出到定义为类加载器的模块。它可能在父层中的一个模块导出的包中。类加载器委托给模块的类加载器,如果该类加载器找不到,则抛出ClassNotFoundException。当调用loadClass来加载不映射到模块的类时,它会委托给父类加载器。

      此方法创建的类加载器在搜索父类加载器之前在定义为类加载器的模块中定位资源(getResourcegetResources和其他资源方法)。

      如果存在安全管理器,则此方法创建的类加载器将以受调用此方法的调用上下文限制的权限加载类和资源。

      参数:
      cf - 层的配置
      parentLayers - 搜索顺序中的父层列表
      parentLoader - 由此方法创建的每个类加载器的父类加载器;对于引导类加载器,可以为null
      返回:
      控制新创建的层的控制器
      抛出:
      IllegalArgumentException - 如果给定配置的父级与父层的配置(包括顺序)不匹配
      LayerInstantiationException - 如果无法创建层,因为配置包含名为"java.base"的模块,或者模块包含名为"java"或以"java."开头的包
      SecurityException - 如果安全管理器拒绝RuntimePermission("createClassLoader")RuntimePermission("getClassLoader")
      参见:
    • defineModules

      public static ModuleLayer.Controller defineModules(Configuration cf, List<ModuleLayer> parentLayers, Function<String,ClassLoader> clf)
      通过将给定Configuration中的模块定义到Java虚拟机来创建一个新的模块层。给定的函数将配置中的每个模块按名称映射到一个类加载器。创建层通知Java虚拟机可以加载哪些类,以便Java虚拟机知道每个类属于哪个模块。

      类加载器由类加载器实现的委托必须遵守模块可读性。类加载器应该是parallel-capable,以避免在加载类时发生死锁。此方法创建新层的实体应该安排类加载器在尝试加载类或资源之前准备好从这些模块加载。

      以下原因可能导致创建层失败:

      • 两个或多个具有相同包的模块映射到同一个类加载器。

      • 一个模块映射到已经定义了同名模块的类加载器。

      • 一个模块映射到已经在模块中的任何包中定义了类型的类加载器。

      此外,如果配置包含名为"java.base"的模块,配置包含具有名为"java"或以"java."开头的包的模块,或者将模块名称映射到类加载器的函数返回null平台类加载器,则无法创建层。

      如果将模块名称映射到类加载器的函数抛出错误或运行时异常,则会传播给此方法的调用者。

      API注释:
      创建具有此方法的层是否是原子操作是特定于实现的。因此,可能会导致此方法在某些模块失败,但不会在所有定义为Java虚拟机的模块中失败。
      参数:
      cf - 层的配置
      parentLayers - 搜索顺序中的父层列表
      clf - 将模块名称映射到类加载器的函数
      返回:
      控制新创建的层的控制器
      抛出:
      IllegalArgumentException - 如果给定配置的父级与父级层的配置(包括顺序)不匹配
      LayerInstantiationException - 如果由于上述任何原因创建层失败
      SecurityException - 如果安全管理器拒绝了RuntimePermission("getClassLoader")
    • configuration

      public Configuration configuration()
      返回此层的配置。
      返回:
      此层的配置
    • parents

      public List<ModuleLayer> parents()
      返回此层父级的不可修改列表,按搜索顺序排列。如果这是空层,则返回一个空列表。
      返回:
      此层父级的可能为空的不可修改列表
    • modules

      public Set<Module> modules()
      返回此层中模块的不可修改集合。
      返回:
      此层中模块的可能为空的不可修改集合
    • findModule

      public Optional<Module> findModule(String name)
      返回此层中具有给定名称的模块,如果不在此层中,则返回层。在父层中查找模块等同于按搜索顺序在每个父层上调用findModule,直到找到模块或搜索所有父层。在层树中,这等同于深度优先搜索。
      参数:
      name - 要查找的模块的名称
      返回:
      具有给定名称的模块或空的Optional(如果在此层或任何父层中没有具有此名称的模块)
    • findLoader

      public ClassLoader findLoader(String name)
      返回具有给定名称的模块的ClassLoader。如果给定名称的模块不在此层中,则按层中指定的方式搜索,findModule

      如果存在安全管理器,则将调用其checkPermission方法,以获得RuntimePermission("getClassLoader")权限,以检查调用者是否被允许访问类加载器。

      API注释:
      此方法不返回Optional<ClassLoader>,因为`null`必须用于表示引导类加载器。
      参数:
      name - 要查找的模块的名称
      返回:
      模块定义的ClassLoader
      抛出:
      IllegalArgumentException - 如果给定名称的模块未在此层或此层的任何父级中定义
      SecurityException - 如果安全管理器拒绝
    • toString

      public String toString()
      返回描述此模块层的字符串。
      覆盖:
      toString 在类 Object
      返回:
      描述此模块层的可能为空的字符串
    • empty

      public static ModuleLayer empty()
      返回层。空层中没有模块。它没有父级。
      返回:
      空层
    • boot

      public static ModuleLayer boot()
      返回引导层。引导层至少包含一个模块,java.base。其父级是层。
      API注释:
      在启动期间和引导层完全初始化之前,此方法返回null
      返回:
      引导层