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