声明:本篇文章参考视频。
一. Jar包与java应用程序
- jar包实际上是一个采用zip标准构建出来的“压缩包”,里面内容包容了程序运行所需的.class文件和相关资源,通常还附加相应的元数据,放到META-INF文件夹中。
- 启动jar包应用程序时,可以在类路径上列出所有使用的JAR
java -classpath 路径列表或jar包列表 -jar要运行的JAR包名.jar
- IDEA Build Artifacts
注意:默认JAR files from Libraies 是extract,正是因为这个选项,因此在运行jar包时,只需
java -jar要运行的JAR包名.jar
最后Build Artifacts,就可以打包了。
二.Java模块化
- 从JDK9开始,JDK9化整为零后,rt.jar(runtime.jar) 被打散为多个模块。打散后的JDK模块,以.jmod作为文件扩展名。
化整为零后:模块化系统允许JVM在运行时仅加载所需的模块,而不是加载整个类路径上的所有类。这可以提高应用程序的启动时间和内存利用率。此外,模块化系统通过明确声明模块之间的依赖关系,可以提供更好的安全性,防止不受信任的代码访问和修改模块之间的内部实现。
查看JDK18,可以发现jmod文件夹。
- 使用模块时,当编译和运行模块时,Java编译器和运行时从模块路径(–module-path)中解析出来正确的模块路径。
如图所示为Intellij编译后的目录结构
模块化以后通过命令行运行java,需要指定–module-path参数,
同时也可以是使用传统的–class-path参数来运行。
注意:
(1)给IntelliJ模块添加“模块依赖”,其实是为了指定编译信息。真正的Java模块依赖信息,是放在module-info.java中的。如下图所示为Intellj添加模块依赖信息,便于编译。
(2)JDK(JPMS)模块和Intellij的module的区别:JPMS模块是传统的 JAR 包加上的额外信息通常包括模块的描述信息,例如模块的名称、依赖的其他模块、导出的包等。被java虚拟机直接管理和装载的,是可以单独运行的程序。例如,模块的名称用于在 Java 虚拟机中唯一标识该模块。依赖的其他模块信息有助于确保在运行时正确加载所需的依赖模块。导出的包信息则控制了哪些包可以被其他模块访问和使用。而Intellij的module是编译单位,包容源代码和资源,是源代码级别的。每一个模块都可以单独生成一个jar包。
- 依赖的传递性
注意:由于采用模块化之后组织了传递依赖,如果想要使得模块具有传递依赖,则在module-info.java 中使用transitive关键字。
transitive:当一个模块(例如模块A)依赖于另一个模块(例如模块B)时,如果B在其模块描述符中使用了transitive声明requires,则A就能读取C中的类型,这是,我们说A"隐式依赖"与C.
module B {
requires transitive C;
}
如果希望项目依赖于java中的所有模块(想要jdk8的运行环境),则可以依赖于java.se。这个模块表示 Java 标准版 (Java SE). 它是一个聚合模块 (只有模块描述文件 module-info.java使用了transititve), 其中引入了许多常用的模块, 包含了大部分 Java SE 规范中定义的 API. 就相当于以前的 rt.jar 。
- 模块描述文件
注意: 由于模块化具有强封装性,因此在com.example包下面有demo文件夹,如果只是exports com.examples,则另一个模块只能访问com.example下的类,而不能访问demo文件夹下的类,如果想要访问,则需要在com.example下module-info.java下继续声明exports com.examples.demo