ModuleFinder
来查找模块。
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
不要求是线程安全的。
- 自 JDK 版本:
- 9
-
Method Summary
Modifier and TypeMethodDescriptionstatic ModuleFinder
compose
(ModuleFinder... finders) 返回由零个或多个模块查找器组成的模块查找器。查找给定名称的模块的引用。findAll()
返回此查找器可以定位的所有模块引用集。static ModuleFinder
返回一个模块查找器,通过搜索一系列目录和/或打包模块来定位文件系统上的模块。static ModuleFinder
ofSystem()
返回一个定位系统模块的模块查找器。
-
Method Details
-
find
查找给定名称的模块的引用。ModuleFinder
提供其定位的模块的一致视图。如果多次调用find
来定位相同模块(按名称),则每次都将返回相同的结果。如果定位了一个模块,则它保证是findAll
方法返回的模块集合的成员。- 参数:
-
name
- 要查找的模块的名称 - 返回:
-
具有给定名称的模块引用,如果未找到则为空的
Optional
- 抛出:
-
FindException
- 如果查找模块时发生错误 -
SecurityException
- 如果被安全管理器拒绝
-
findAll
Set<ModuleReference> findAll()返回此查找器可以定位的所有模块引用集。ModuleFinder
提供其定位的模块的一致视图。如果多次调用findAll
,则每次都将返回相同(相等)的结果。对于返回集合中的每个ModuleReference
元素,如果调用find
来查找该模块,则保证会定位到ModuleReference
。- API 注意:
-
对于需要扫描模块路径以查找提供特定服务的模块的方法(例如
resolveAndBind
),这一点非常重要。 - 返回:
- 此查找器定位的所有模块引用集
- 抛出:
-
FindException
- 如果查找所有模块时发生错误 -
SecurityException
- 如果被安全管理器拒绝
-
ofSystem
返回一个定位系统模块的模块查找器。系统模块是Java运行时映像中的模块。模块查找器将始终找到java.base
。如果设置了安全管理器,则将调用其
checkPermission
方法来检查调用者是否被授予访问系统模块的RuntimePermission("accessSystemModules")
权限。- 返回:
-
定位系统模块的
ModuleFinder
- 抛出:
-
SecurityException
- 如果被安全管理器拒绝
-
of
返回一个模块查找器,通过搜索一系列目录和/或打包模块来定位文件系统上的模块。给定数组中的每个元素是以下之一:-
模块目录的路径。
-
爆炸模块的顶级目录的路径。
-
打包模块的路径。
如果一个元素是模块目录的路径,那么目录中的每个条目都是打包模块或爆炸模块的顶级目录。如果一个目录包含多个具有相同名称的模块,则会报错。如果一个元素是目录的路径,并且该目录包含名为
module-info.class
的文件,则该目录将被视为爆炸模块而不是模块目录。此方法返回的模块查找器支持打包为JAR文件的模块。具有
module-info.class
在其顶级目录或在多版本 JAR文件中的版本化条目中的JAR文件是模块化JAR文件,因此定义了一个显式模块。没有module-info.class
在其顶级目录中的JAR文件定义为自动模块,如下所示:-
如果JAR文件的主清单中具有属性"
Automatic-Module-Name
",则其值为模块名称。否则,模块名称将从JAR文件的名称派生。 -
版本
,以及当属性"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文件包含JAR文件顶级目录中的.class
,服务配置文件中的条目不是合法的类名或其包名不在为模块派生的包集合中时,可能会出现这种情况。除了JAR文件外,实现还可以支持打包在其他实现特定模块格式中的模块。如果传递给此方法的数组中的元素是模块目录的路径,则将忽略目录中未被识别为模块的条目。如果数组中的元素是未被识别的打包模块的路径,则在遇到该文件时将抛出
FindException
。不存在的文件路径始终会被忽略。与自动模块一样,打包或爆炸模块的内容可能需要进行扫描以确定模块中的包。是否忽略隐藏文件是实现特定的,因此未指定。如果在顶级目录中找到
.class
文件(除了module-info.class
),则假定它是未命名包中的类,因此会抛出FindException
。此方法创建的查找器是惰性的,不会急切地检查给定的文件路径是否为目录或打包模块。因此,只有在调用这些方法导致搜索目录或打包模块并遇到错误时,
find
或findAll
方法才会失败。- 参数:
-
entries
- 可能为空的目录路径数组,包含模块目录或打包或爆炸模块的路径 - 返回:
-
定位文件系统上模块的
ModuleFinder
-
-
compose
返回一个由零个或多个模块查找器序列组成的模块查找器。结果模块查找器的find
方法将通过调用每个模块查找器的find
方法(按照数组索引顺序)来定位模块,直到找到模块或所有模块查找器都已搜索完毕。结果模块查找器的findAll
方法将返回一个包含由第一个模块查找器定位的所有模块的集合。该集合将包括由第二个或后续模块查找器定位的所有模块,这些模块不是由前面的模块查找器在序列中定位的。在定位模块时,由底层模块查找器的
find
或findAll
方法抛出的任何异常或错误将传播到结果模块查找器的find
或findAll
方法的调用者。- 参数:
-
finders
- 模块查找器数组 - 返回:
-
组成模块查找器序列的
ModuleFinder
-