ModuleFinder
用于在 resolution 或 服务绑定 期间查找模块。
ModuleFinder
只能找到一个具有给定名称的模块。例如,在一系列目录中查找模块的 ModuleFinder
将定位给定名称的模块的第一次出现,并将忽略出现在该序列后面的目录中的具有该名称的其他模块。
用法示例:
Path dir1 = ..., dir2 = ..., dir3 = ...;
ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
Optional<ModuleReference> omref = finder.find("jdk.foo");
omref.ifPresent(mref -> ... );
此处定义的 find
和 findAll
方法可能因多种原因而失败。这些包括 I/O 错误、在解析模块描述符 (module-info.class
) 时检测到的错误,或者在 ModuleFinder.of
返回的 ModuleFinder
的情况下,在目录中找到两个或更多同名模块。当检测到错误时,这些方法会抛出 FindException
和适当的 cause
。抛出 FindException
后 ModuleFinder
的行为未定义。例如,在抛出异常后调用 find
可能会也可能不会扫描导致异常的相同模块。建议在抛出异常后丢弃模块查找器。
ModuleFinder
不需要是线程安全的。
- 自从:
- 9
-
方法总结
修饰符和类型方法描述static ModuleFinder
compose
(ModuleFinder... finders) 返回由零个或多个模块查找器序列组成的模块查找器。查找对给定名称的模块的引用。findAll()
返回此查找器可以定位的所有模块引用的集合。static ModuleFinder
返回一个模块查找器,它通过搜索一系列目录和/或打包模块在文件系统上定位模块。static ModuleFinder
ofSystem()
返回定位 system modules 的模块查找器。
-
方法详情
-
find
查找对给定名称的模块的引用。ModuleFinder
提供了它所定位的模块的一致视图。如果多次调用find
来定位同一个模块(按名称),那么它每次都会返回相同的结果。如果找到一个模块,那么它保证是findAll
方法返回的模块集的成员。- 参数:
name
- 要查找的模块的名称- 返回:
-
对具有给定名称的模块的引用,如果未找到则为空
Optional
- 抛出:
FindException
- 如果查找模块时出错SecurityException
- 如果安全经理拒绝
-
findAll
Set <ModuleReference > findAll()返回此查找器可以定位的所有模块引用的集合。ModuleFinder
提供了它所定位的模块的一致视图。如果多次调用findAll
,则每次都会返回相同(等于)的结果。对于返回集合中的每个ModuleReference
元素,如果调用以查找该模块,则保证find
将定位ModuleReference
。- API 注意:
-
这对于需要扫描模块路径以查找提供特定服务的模块的
resolveAndBind
等方法来说很重要。 - 返回:
- 此查找器定位的所有模块引用的集合
- 抛出:
FindException
- 如果查找所有模块时出错SecurityException
- 如果安全经理拒绝
-
ofSystem
返回定位 system modules 的模块查找器。系统模块是 Java 运行时映像中的模块。模块查找器将始终找到java.base
。如果设置了安全管理器,则调用其
checkPermission
方法来检查调用者是否已被授予RuntimePermission("accessSystemModules")
访问系统模块的权限。- 返回:
-
定位系统模块的
ModuleFinder
- 抛出:
SecurityException
- 如果安全经理拒绝
-
of
返回一个模块查找器,它通过搜索一系列目录和/或打包模块在文件系统上定位模块。给定数组中的每个元素都是以下之一:模块目录的路径。
exploded module 的 top-level 目录的路径。
packaged module 的路径。
如果元素是模块目录的路径,则目录中的每个条目都是打包模块或分解模块的顶级目录。如果目录包含多个具有相同名称的模块,则会出错。如果元素是目录的路径,并且该目录包含名为
module-info.class
的文件,则该目录将被视为展开的模块而不是模块目录。此方法返回的模块查找器支持打包为 JAR 文件的模块。在其顶级目录中或在 多版本 JAR 文件中的版本化条目中具有
module-info.class
的 JAR 文件是模块化 JAR 文件,因此定义了一个 explicit 模块。在其顶级目录中没有module-info.class
的 JAR 文件定义了一个 automatic module ,如下所示:如果 JAR 文件在其主清单中具有属性“
Automatic-Module-Name
”,则其值为 模块名称。模块名称是从 JAR 文件的名称派生的。version
和属性“Automatic-Module-Name
”不存在时的模块名称源自 JAR 文件的文件名,如下所示:“
.jar
”后缀已删除。如果名称与正则表达式
"-(\\d+(\\.|$))"
匹配,则模块名称将从第一次出现的连字符之前的子序列派生。连字符后的子序列被解析为Version
并且如果不能被解析为Version
则被忽略。模块名称中的所有非字母数字字符 (
[^A-Za-z0-9]
) 都替换为一个点 ("."
),所有重复的点都替换为一个点,并删除所有前导和尾随的点。例如,一个名为“
foo-bar.jar
”的 JAR 文件将派生一个模块名称“foo.bar
”并且没有版本。名为“foo-bar-1.2.3-SNAPSHOT.jar
”的 JAR 文件将导出模块名称“foo.bar
”和“1.2.3-SNAPSHOT
”作为版本。
模块中的包集派生自 JAR 文件中名称以“
.class
”结尾的非目录条目。候选包名称是从名称派生而来的,使用的字符最多但不包括最后一个正斜杠。所有剩余的正斜杠都替换为点 ("."
)。如果生成的字符串是合法的包名,则假定它是包名。例如,如果 JAR 文件包含条目“p/q/Foo.class
”,则派生的包名称为“p.q
”。以
META-INF/services/
开头的条目的内容被假定为服务配置文件(请参阅ServiceLoader
)。如果文件名(跟在META-INF/services/
之后)是合法的类名,则假定它是服务类型的完全限定类名。假定文件中的条目是提供程序类的完全限定类名。如果 JAR 文件在其主清单中有一个
Main-Class
属性,它的值是一个合法的类名,并且它的包在为模块派生的包集中,那么该值就是模块 主类 。
如果无法为自动模块创建
ModuleDescriptor
(通过ModuleDescriptor.Builder
API),则抛出FindException
。当“Automatic-Module-Name
”属性的值不是合法的模块名称时,可能会出现这种情况,无法从 JAR 文件的文件名派生出合法的模块名称,其中 JAR 文件的顶级目录中包含一个.class
JAR 文件,其中服务配置文件中的条目不是合法的类名或其包名不在为模块派生的包集中。除了 JAR 文件之外,实现还可以支持以其他实现特定模块格式打包的模块。如果为此方法指定的数组中的元素是模块目录的路径,则目录中未被识别为模块的条目将被忽略。如果数组中的元素是无法识别的打包模块的路径,则在遇到该文件时抛出
FindException
。始终忽略不存在的文件路径。与自动模块一样,打包或分解模块的内容可能需要 scanned 才能确定模块中的包。 隐藏文件 是否被忽略是特定于实现的,因此未指定。如果在顶级目录中找到
.class
文件(module-info.class
除外),则假定它是未命名包中的类,因此抛出FindException
。通过这种方法创建的查找器是惰性的,不会急切地检查给定的文件路径是目录还是打包模块。因此,
find
或findAll
方法只有在调用这些方法导致搜索目录或打包模块并遇到错误时才会失败。- 参数:
entries
- 一个可能为空的模块目录路径数组或打包或分解模块的路径- 返回:
-
在文件系统上定位模块的
ModuleFinder
-
compose
返回由零个或多个模块查找器序列组成的模块查找器。生成的模块查找器的find
方法将通过调用每个模块查找器的find
方法来定位模块,按照数组索引顺序,直到找到模块或搜索到所有模块查找器。结果模块查找器的findAll
方法将返回一组模块,其中包括第一个模块查找器找到的所有模块。模块集将包括序列中先前模块查找器未找到的第二个或后续模块查找器找到的所有模块。当定位模块时,底层模块查找器的
find
或findAll
方法抛出的任何异常或错误都将传播到结果模块查找器的find
或findAll
方法的调用者。- 参数:
finders
- 模块查找器数组- 返回:
-
一个
ModuleFinder
组成了一系列模块查找器
-