1. java9后JDK后目录的变化
不见了jre,新增了jmods目录。
1)为什么不见了jre?
新版JDK提供了 jlink工具,使用它构建一个包含jre镜像的应用程序。 就是可以打包一个引用程序内部已经包含完整或部分jre,可以直接运行。
2)我们都知道rt.jar文件是java的基础类库,那rt.jar去哪里了?
rt.jar在java9后被拆分并采用模块化的方式被打包成了一个个.jmod文件(${JAVA_HOME}/jmods目录下)。如下:
3)为什么要拆rt.jar呢?
1.rt.jar文件的大小超过了60M(java8)。
2.模块化以后也更适合构建jre镜像的应用程序,可以根据选择需要的jre模 块,而不必打包全部jre。
2. java模块化的理解
一、 提供了一种新的代码组织方式。
如图我们将代码文件打包成一个一个jmod,服务提供方控制接口的暴漏规则,而 服务消费方通过类似依赖引入。具体下一节我们具体操作一下。
二、 提供了一种新的代码权限级别,增强了代码权限控制。
1、java原有的文件代码权限如下:
public:表示紧跟其后的成员可以被任何人引用
private:表示紧跟其后的成员除了类型创建者和类型内部的方法,任何人都不可引 用,否者程序编译报错
protected:表示子类访问权限,同包中的可以访问,即使不同包,但是有继承关系,也 可以访问.
默认访问权限(即定义属性时不加任何关键字修饰):默认访问权限通常被称为 “包访问权限”,在这种权限下的成员变量可被同一个包中的其他类访问
2、模块化的代码权限控制我们通过以下模块提供的两个指令就能看出:
(1)exports 和 exports to 指令
exports 指令用于指定一个模块中哪些包对外是可访问的,而 exports…to 指令则 用来限定哪些模块可以访问导出类,允许开发者通过逗号分隔的列表指定哪些模 块及模块的哪些代码可以访问导出的包。
(2) provides…with 指令
该指令用于说明模块提供了某个服务的实现,因此模块也称为服务提供者。 provides 后面跟接口名或抽象类名,与 use 指令后的名称一致,with 后面跟实现 类该接口或抽象类的类名。
备注:java 模块暂不支持对对版本的管理。
3. 提供模块间依赖的管理
执行如下指令,显示该模块的引用与输出:
java -d java.logging
4. 打包jre镜像程序,可以任意运行
java模块的语法
-
[open] module <module>:
声明一个模块,模块名称应全局唯一,不可重复。加上 open 关键词表示模块内的所有包都允许通过 Java 反射访问,模块声明体内不再允许使用 opens 语句。
-
requires [transitive] <module>:
声明模块依赖,一次只能声明一个依赖,如果依赖多个模块,需要多次声明。加上 transitive 关键词表示传递依赖,比如模块 A 依赖模块 B,模块 B 传递依赖模块 C,那么模块 A 就会自动依赖模块 C,类似于 Maven。
-
exports <package> [to <module1>[, <module2>...]]:
导出模块内的包(允许直接 import 使用),一次导出一个包,如果需要导出多个包,需要多次声明。如果需要定向导出,可以使用 to 关键词,后面加上模块列表(逗号分隔)。
-
opens <package> [to <module>[, <module2>...]]:
开放模块内的包(允许通过 Java 反射访问),一次开放一个包,如果需要开放多个包,需要多次声明。如果需要定向开放,可以使用 to 关键词,后面加上模块列表(逗号分隔)。
-
provides <interface | abstract class> with <class1>[, <class2> ...]:
声明模块提供的 Java SPI 服务,一次可以声明多个服务实现类(逗号分隔)。
-
uses <interface | abstract class>:
声明模块依赖的 Java SPI 服务,加上之后模块内的代码就可以通过 ServiceLoader.load(Class) 一次性加载所声明的 SPI 服务的所有实现类。
5. java模块的例子
该例子用来让您尽快对java模块的功能和使用场景有一个认知。
1)新建一个maven项目,名字是JmoduleTest 。
2)编写main.java
package org.example;public class Main {public static void main(String[] args) {System.out.println("Hello world!");}
}
3) 创建module-info.java 类,并且依赖java.base, java.logging。 java.base默认就有。
4) 将模块信息和类编译后放入bin目录下
javac -d bin src/module-info.java src/main/java/org/example/*.java
5) 创建demo.jar,并指定主类和编译class
jar --create --file demo.jar --main-class org.example.Main -C bin .
打包后,生成demo.jar文件
6 ) 创建模块
jmod create --class-path demo.jar demo.jmod
之后会生成demo.jmod。
7) 运行demo
java --module-path demo.jar --module JmoduleTest
运行结果是:
8 ) 创建jre镜像
#--module-path参数指定了我们自己的模块hello.jmod,然后,在--add-modules参数中指定了我们用到的3个模块java.base、java.xml和hello.world,用逗号分隔。最后,在--output参数指定输出目录。
jlink --module-path demo.jmod --add-modules java.base,java.logging, JmoduleTest --output jre
9 ) 执行镜像
#我的是window是环境下,执行生成jre中的java命令
.\jre\bin\java --module JmoduleTest
10 ) 查看模块信息
./jre/bin/java -d JmoduleTest
参考资料
Understanding Java 9 Modules | Oracle United Kingdom