diff --git a/source/_posts/nf-java9.md b/source/_posts/nf-java9.md index bba645b..75b314a 100644 --- a/source/_posts/nf-java9.md +++ b/source/_posts/nf-java9.md @@ -85,9 +85,9 @@ String readData(String message) throws IOException { ## 模块系统 -模块系统是Java 9所做的最大改变,模块是代码和数据的封装,其中代码被组织为多个包,数据则包含资源文件和其他静态信息。Java 9编译得到的最终Artifact可以是Jar文件,也可以是模块系统引入的新增的JMOD文件。 +模块系统是Java 9所做的最大改变,模块是代码和数据的封装,其中代码被组织为多个包,数据则包含资源文件和其他静态信息。就像是包是类和接口的容器一样,模块就是包的容器。Java 9编译得到的最终Artifact可以是Jar文件,也可以是模块系统引入的新增的JMOD文件。 -模块的根目录中需要放置一个`module-info.java`文件来描述模块,该文件在编译后位于模块Artifact的根目录中。在这个文件中可以使用关键字`module`声明一个模块,例如以下示例。 +模块的根目录中需要放置一个`module-info.java`文件来描述模块,该文件在编译后位于模块Artifact的根目录中,在编写这个文件的时候,通常需要解决的两个问题是模块的依赖和模块的导出。在这个文件中可以使用关键字`module`声明一个模块,例如以下示例。 ```java module xyz.archgrid.samplemodule { @@ -104,10 +104,27 @@ module xyz.archgrid.samplemodule { 模块描述中可以使用以下关键字来控制其他应用对包内内容的访问。 * `exports`,选择需要导出的类。 -* `requires`,引用其他的模块。需要注意的是,`java.base`会被默认加入引用,不需要显式书写。每个模块仅会被引入一次,并且只能访问已经导出的类。 +* `exports ... to ...`,选择需要导出的类,并将其导出给特定包访问。 +* `requires`,引用其他的模块。需要注意的是,`java.base`会被默认加入引用,不需要显式书写。每个模块仅会被引入一次,并且只能访问已经导出的类。`requires`关键字还可以搭配其他的关键字来实现更加精细的控制。 + * `requires transitive`,依赖传递,这表示任何依赖于本模块的的应用,也可以查看和使用声明为依赖传递的包。 + * `requires static`,声明静态依赖,如果指定的依赖项在模块路径上可见,那么当前模块就可以使用它,如果不可见,那也不会发生错误。 +* `uses`,指定当前模块需要使用的服务。服务是实现了`uses`指令指定的接口或者继承了`uses`指令指定的抽象类的对象。 +* `provides ... with ...`,使指定的模块成为服务的提供者。其中`provides`部分指定模块的`uses`关键字列出接口和抽象类,`with`部分则指定实现接口或者扩展抽象类的服务提供类的命令。 +* `opens`,将模块中的包设为公开的,因为在默认情况下,JPMS中的包都是私有的。 +* `opens ... to ...`,将模块中的包指定开放给特定的包,仅允许特定的包有全部访问权。 +* `open module`,将整个模块都开放出来。 被依赖模块可以通过命令`jar --create --file 目标jar文件 -C 已编译目录 要打包内容`来完成打包。依赖其他模块的模块可以通过命令`javac -p 依赖模块目录 -d 输出目录 源文件集`来完成编译,并使用命令`jar --create -f 目标jar文件 -p 依赖模块目录 --main-class 主类 -C 已编译目录 要打包内容`。在运行最终的模块时需要指定所有模块的位置,例如`java -p 主模块:依赖模块 -m 主类`。 +因为JPMS的引入,所以使用了JPMS的应用与没有使用JPMS的第三方库之间还存在着一定的兼容性问题,并且JPMS在使用中需要注意以下问题。 + +* 所有使用`module-info`的文件仅适用于在模块路径上使用模块化的jar。 +* 模块的版本是不能够被处理的,这也就是说相同的模块名称是不能够被加载两次的。 +* 两个模块可能包含不相同的包。 +* 在编译和运行的时候,模块之间不能有循环依赖出现。 +* 非公共字段和方法将不能通过反射访问。 +* 在模块化的应用中使用没有模块化的第三方库,需要使用其jar包名称作为其模块名称。 + ## 兼容Jar包 兼容Jar包可以允许创建针对不同的Java环境选择不同class版本的Jar包。要创建兼容Jar包,需要在`MANIFEST.MF`文件中使用增加的属性:`Multi-Release: true`。此外还需要在`META-INF`目录中增加一个名为`versions`目录用于存放针对不同版本JRE的class文件。