我对Java9模块的理解

一、前言

主要介绍Java 9平台模块系统(JPMS: Java 9 Platform Module System),它是Java自诞生以来最重要的新软件工程技术。是模块化项目Jigsaw的产物,帮助开发人员在构建、维护和扩展软件系统(尤其是大型系统)时提高生产力。

二、历史

Java SE自1995年诞生以来,从用于资源受限设备的小型应用程序(如物联网(IoT)和其他嵌入式设备中的应用程序)到关键业务和关键任务系统等大型应用程序,一应俱全。随着发展,java有大量的遗留代码,但是直到现在,Java平台一直提供一站式的解决方案。但很多时候很多功能并没有被广泛使用,但是Java平台也没能使用模块化,因此诞生了Project Jigsaw^1

Java SE平台的模块化一直很难实现。 JSR 277:在2005年的Java 7第一次提出了Java模块系统。此JSR后来被JSR 376:Java Platform Module System取代,并打算在Java 8实现。Java 8 发布的时候并没有带来JPMS,但是带来了JEP 161: Compact Profiles(定义Java SE平台规范的一些概要,可以不需要整个平台,应用程序就可以部署和运行在小型设备上。)

我们可以简单看出Oracle将Java API定义了三个紧凑配置,感兴趣可以自行查阅相关资料。

1
2
3
4
5
6
7
8
compact1                     compact2                    compact3
-------------------------- ----------------------- --------------------------
java.io java.rmi java.lang.instrument
java.lang.annotation java.rmi.activation java.lang.management
java.lang.invoke java.rmi.dgc java.security.acl
java.lang.ref java.rmi.registry java.util.prefs
java.lang.reflect java.rmi.server javax.annotation.processing
.... .... ....

JPMS最终推迟到了2017年9月,在Java 9中得以实现。

三、快速上手

1. 传统项目

在模块化出来之前,我们的项目运行依赖于各种class或者jar文件,如当我们编译完SpringBoot项目,由于其依赖了各种starter,我们的运行命令是这样的:

image-20210422230635304

可以看出,**-classpath**后面的参数除了我们项目编译后class文件夹外,还有各种第三方的jar包,密密麻麻,好在有Maven、Gradle等这类自动构建工具帮我们打包生成清单文件,最终生成的jar包,我们要运行仅需输入如:java -jar jeremy.jar便可运行我们的项目。

2. Java module项目

创建一个Java工程,新建主类com.jeremytsai.module.App

1
2
3
4
5
public class App {
public static void main(String[] args) {
System.out.println("Hello module.");
}
}

src下创建module-info.java文件

1
2
module jeremy {
}

编译项目,生成字节码文件

1
2
3
4
5
6
│  module-info.class

└─com
└─jeremytsai
└─module
App.class

运行模块

1
2
java -p . -m jeremy/com.jeremytsai.module.App
Hello module.

至此,我们就完成的第一个模块的开发。其中**-p后面的参数是模块路径-m后面的是<模块>[/<主类>]**。

3. 传统项目与Java module项目的区别

传统项目是

1
package -> class/interface

Java module 项目是

1
module -> package -> class/interface

我们反编译module-info.class看看

1
2
3
module jeremy {
requires java.base;
}

多了一个默认项,requires java.base;,意思指的是运行我们这个项目仅需java.base这个模块即可,这样我们就可用只包含java.base模块的jre加上我们的代码便可以运行我们的项目。非模块项目的jre是不能精简的。

JDK8 中包含有完整jre,其中rt.jar是非常大的,在1.8.0_202版本中有60.6MB,而JDK9中并没有jre,取而代之的是jmods文件夹。

1
2
3
4
java.activation.jmod
java.base.jmod
java.compiler.jmod
...

这里能看到我们所需要依赖的 java.base。有了这些java 模块,我们就可以打包运行我们项目所需的最小环境,这样在资源受限的小型设备中就能有更好的发挥。

四、JPMS的特性

Project Jigsaw的主要目标是:

  • 使开发人员更轻松地构建和维护库和大型应用程序

  • 总体上提高Java SE平台实现(特别是JDK)的安全性和可维护性

  • 改善应用程序性能

  • 使Java SE Platform和JDK能够按比例缩小规模,以用于小型计算设备和密集型云部署。

这里重点讲讲安全性问题,以往我们可以通过反射获取各种公开/非公开的属性/方法,由于public属性的存在,Java过于开放。经常访问到一些非核心/内部使用的公开API。

引入JPMS后,我们只能访问模块公开的API,开发者也可以很好隐藏自己内部public的一些非关键的API了。也能有效阻止反射获取私有属性/字段。反射在编译过程并不会报错,即便**setAccessible(true)**,最终还是得到 InaccessibleObjectException运行时异常。