层是根据 Configuration 中的模块图和将每个模块映射到 ClassLoader 的函数创建的。创建一个层通知 Java 虚拟机关于可以从模块加载的类,以便 Java 虚拟机知道每个类是哪个模块的成员。
创建层会为配置中的每个 ResolvedModule 创建一个 Module 对象。对于每个已解析的模块,即 read 、Module reads 对应的运行时 Module,它们可能位于同一层或 parent 层。
defineModulesWithOneLoader 和 defineModulesWithManyLoaders 方法提供了创建模块层的便利方法,其中所有模块都映射到单个类加载器,或者每个模块都映射到自己的类加载器。 defineModules 方法适用于更高级的情况,其中模块通过指定给该方法的函数映射到自定义类加载器。这些方法中的每一个都有一个实例和静态变体。实例方法创建一个以接收器为父层的层。静态方法适用于更高级的情况,其中可以有多个父层或需要 Controller 来控制层中的模块
一个Java虚拟机至少有一个非空层,即boot 层,它是在Java虚拟机启动时创建的。引导层包含模块 java.base,并且是 Java 虚拟机中唯一具有名为“java.base”的模块的层。引导层中的模块被映射到 Java 虚拟机中的引导类加载器和其他类加载器。创建附加层时,引导层通常是parent 。
创建层中的每个Module,以便它exports 和opens 由其ModuleDescriptor 描述的包。合格的导出(包导出到一组目标模块而不是所有模块)在创建层时具体化如下:
- 如果模块
X将包导出到Y,并且如果运行时ModuleX读取ModuleY,则包将导出到ModuleY(可能与X在同一层或父层)。 - 如果模块
X将包导出到Y,并且如果运行时ModuleX不读取Y,则目标Y就像调用findModule在层或其父层中查找模块一样定位。如果找到Y,则将包导出到找到的Y实例。如果未找到Y,则忽略合格的导出。
合格的打开与合格的输出以相同的方式处理。
与创建 Configuration 一样,automatic 模块在创建层时会受到特殊对待。在 Java 虚拟机中创建一个自动模块作为Module,它读取 Java 虚拟机中每个未命名的 Module。
除非另有说明,否则将 null 参数传递给此类中的方法会导致抛出 NullPointerException 。
示例
此示例通过将引导层的配置作为父级解析名为“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");
- 自从:
- 9
- 参见:
-
内部类总结
内部类 -
方法总结
修饰符和类型方法描述static ModuleLayerboot()返回引导层。返回该层的配置。defineModules(Configuration cf, Function<String, ClassLoader> clf) 通过将给定Configuration中的模块定义到 Java 虚拟机,创建一个新的模块层,并将该层作为其父层。static ModuleLayer.ControllerdefineModules(Configuration cf, List<ModuleLayer> parentLayers, Function<String, ClassLoader> clf) 通过将给定Configuration中的模块定义到 Java 虚拟机来创建一个新的模块层。defineModulesWithManyLoaders(Configuration cf, ClassLoader parentLoader) 通过将给定Configuration中的模块定义到 Java 虚拟机,创建一个新的模块层,并将该层作为其父层。static ModuleLayer.ControllerdefineModulesWithManyLoaders(Configuration cf, List<ModuleLayer> parentLayers, ClassLoader parentLoader) 通过将给定Configuration中的模块定义到 Java 虚拟机来创建一个新的模块层。defineModulesWithOneLoader(Configuration cf, ClassLoader parentLoader) 通过将给定Configuration中的模块定义到 Java 虚拟机,创建一个新的模块层,并将该层作为其父层。static ModuleLayer.ControllerdefineModulesWithOneLoader(Configuration cf, List<ModuleLayer> parentLayers, ClassLoader parentLoader) 通过将给定Configuration中的模块定义到 Java 虚拟机来创建一个新的模块层。static ModuleLayerempty()返回 empty 层。findLoader(String name) 返回具有给定名称的模块的ClassLoader。findModule(String name) 返回该层中具有给定名称的模块,如果不在该层中,则返回 parent 层。modules()返回该层中一组不可修改的模块。parents()按搜索顺序返回该图层父级的不可修改列表。toString()返回描述此模块层的字符串。
-
方法详情
-
defineModulesWithOneLoader
通过将给定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
通过将给定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
通过将给定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 虚拟机来创建一个新的模块层。此方法创建一个类加载器并为该类加载器定义所有模块。通过此方法创建的类加载器在从模块加载类时实现了direct delegation。如果调用
loadClass方法来加载类,则它使用类的包名称将其映射到模块。这可能是这一层中的一个模块,因此定义到同一个类加载器。它可以是父层中模块中的包,导出到该层中的一个或多个模块。类加载器委托给模块的类加载器,如果该类加载器未找到则抛出ClassNotFoundException。当调用loadClass来加载未映射到模块的类时,它会委托给父类加载器。该方法创建的类加载器在查找父类加载器之前,先定位层内所有模块中的资源(
getResource、getResources等资源方法)。尝试创建一个所有模块都定义为同一个类加载器的层可能会失败,原因如下:
Overlapping packages:配置中的两个或多个模块具有相同的包。
Split delegation:生成的类加载器需要委托给多个类加载器才能加载特定包中的类。
此外,如果配置包含名为“
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是给定的父类加载器。通过此方法创建的类加载器在从模块加载类时实现 direct delegation。如果调用
loadClass方法来加载类,则它使用类的包名称将其映射到模块。包可能在为类加载器定义的模块中。该包可以由该层中的另一个模块导出到定义给类加载器的模块。它可能位于父层中的模块导出的包中。类加载器委托给模块的类加载器,如果该类加载器未找到则抛出ClassNotFoundException。当调用loadClass来加载未映射到模块的类时,它会委托给父类加载器。通过此方法创建的类加载器在搜索父类加载器之前在定义给类加载器的模块中定位资源(
getResource、getResources和其他资源方法)。如果有安全管理器,则由此方法创建的类加载器将加载具有受此方法的调用上下文限制的特权的类和资源。
- 参数:
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
返回该层的配置。- 返回:
- 该层的配置
-
parents
按搜索顺序返回该图层父级的不可修改列表。如果这是 空层,则返回一个空列表。- 返回:
- 该层父级的可能为空的不可修改列表
-
modules
返回该层中一组不可修改的模块。- 返回:
- 该层中一组可能为空的不可修改的模块
-
findModule
返回该层中具有给定名称的模块,如果不在该层中,则返回 parent 层。在父层中查找模块相当于按搜索顺序在每个父层上调用findModule,直到找到模块或搜索到所有父层。在 tree of layers 中,这相当于深度优先搜索。- 参数:
name- 要查找的模块的名称- 返回:
-
具有给定名称的模块或一个空的
Optional如果在该层或任何父层中没有具有该名称的模块
-
findLoader
返回具有给定名称的模块的ClassLoader。如果给定名称的模块不在该层中,则以findModule指定的方式搜索parent层。如果有安全管理器,则使用
RuntimePermission("getClassLoader")权限调用其checkPermission方法,以检查是否允许调用者访问类加载器。- API 注意:
-
此方法不返回
Optional<ClassLoader>,因为必须使用“null”来表示引导类加载器。 - 参数:
name- 要查找的模块的名称- 返回:
- 定义模块的 ClassLoader
- 抛出:
IllegalArgumentException- 如果给定名称的模块未在该层或该层的任何父级中定义SecurityException- 如果安全经理拒绝
-
toString
返回描述此模块层的字符串。 -
empty
返回 empty 层。空层中没有模块。它没有父母。- 返回:
- 空层
-
boot
返回引导层。引导层至少包含一个模块,java.base。它的父级是empty层。- API 注意:
-
此方法在启动期间和引导层完全初始化之前返回
null。 - 返回:
- 引导层
-