前言Moudle
模块的申明模块访问控制
exportsopens 声明依赖
requires 服务消费
usesprovides
前言模块化(Module),项目名字叫做Jigsaw(拉锯),拉了多年的锯,终于把java锯成了一个个模块。到jdk1.8,jre的rt.jar已经有65M了,运行一个HelloWorld也需要近百兆的JRE环境。还有就是jar hell。就是类路径重复造成的:
- Libary中jar包改名了,新老jar包一起,不容易识别。jar包间存在传递依赖有些类在jar包间复制使用
模块化可以将jar声明为模块,它将在其自己的隔离类加载器中运行,该类加载器以OSGI方式从其他类似的模块类加载器读取类文件。这将允许同一版本的Jar的多个版本共存。
Moudle 模块的申明模块名只要是合法java标识符就可以,和同名的类名、包名、变量名不冲突。
//以包路径命名
module jdk.compiler1 {}
//一个名叫module的模块
module module{}
//var不与int var冲突
module var{}
模块访问控制
导出(exports)和开放(opens)语句用于控制对模块代码的访问。
exports表示允许在编译时和运行时访问指定包的public成员。
- 如果一个模块声明中的多个exports指令指定了相同的包名,则这是一个编译时错误。指定的包exports未由与当前模块关联的编译单元声明,则为编译时错误
exports willem.com.sun.source.tree;
//将javac.api导出给jdk.javadoc和jdk.jshell模块
exports willem.com.sun.tools.javac.api to
jdk.javadoc,
jdk.jshell;
opens
opens用于声明该模块的指定包在运行时(而不是编译期)允许使用反射访问。
module java.house {
// 所有模块都可以在运行时使用反射访问com.xhx.house模块
opens com.xhx.house;
//com.xhx.user可以在运行时使用反射访问com.xhx.house模块
opens com.xhx.house to com.xhx.user;;
}
open的作用是表示该模块下的所有的包在runtime都允许深度反射(包括public及private类型) 但是编译时期不可以。但是编译时期,仅仅允许该module中声明过exports的包可以访问,如果没有exports则该包的类在编译时期不可读。
open java.house {
//里面不能再使用opens了,因为整个包都已经open了,可以用exports
}
声明依赖
requires
指定当前模块所依赖的模块。requires transitive java.compiler和requires java.compiler都是申明了依赖,但前一个具有传递性,如果有模块依赖
jdk.compiler1,但没有直接申明依赖java.compiler,它仍然可以读取java.compiler模块。如果没有transitive而且也没显示声明依赖java.compiler就无法读取此模块。
module jdk.compiler1 {
requires transitive java.compiler;
}
服务消费
uses
uses
module jdk.compiler1 {
//javac编译器使用它提供平台服务。
uses willem.com.sun.tools.javac.platform.PlatformProvider;
}
provides
该服务可以在当前模块或另一个模块中声明。如果服务未在当前模块中声明,则该服务必须可被当前模块中的代码访问,否则发生编译错误。每个服务提供者必须是顶级或静态的公共类或接口,否则会发生编译时错误。
//结合上面的uses,模块内部自己提供服务,自己使用,也可以一个模块提供,一个使用
module jdk.compiler1 {
provides willem.com.sun.tools.javac.platform.PlatformProvider with
willem.com.sun.tools.javac.platform.JDKPlatformProvider;
}
这是JDKPlatformProvider中提供平台支持JDK版本的核心代码。如果没有module-info.java中的服务提供发现机制,编译器就无法指定对应的jdk版本
static {
SUPPORTED_JAVA_PLATFORM_VERSIONS = new TreeSet<>(NUMERICAL_COMPARATOR);
Path ctSymFile = findCtSym();
if (Files.exists(ctSymFile)) {
try (FileSystem fs = FileSystems.newFileSystem(ctSymFile, (ClassLoader)null);
DirectoryStream dir =
Files.newDirectoryStream(fs.getRootDirectories().iterator().next())) {
for (Path section : dir) {
if (section.getFileName().toString().contains("-"))
continue;
for (char ver : section.getFileName().toString().toCharArray()) {
String verString = Character.toString(ver);
Target t = Target.lookup("" + Integer.parseInt(verString, Character.MAX_RADIX));
if (t != null) {
SUPPORTED_JAVA_PLATFORM_VERSIONS.add(targetNumericVersion(t));
}
}
}
} catch (IOException | ProviderNotFoundException ex) {
}
}
}
明明在jdk17中却不支持17,就是平台服务未被发现



