Java SE 9 引入了 Java 模块系统。它不应与 maven 或 IntelliJ Idea 等的模块混淆。Java SE 9 模块是直接支持 Java 的新功能。
在本文中,我们将快速介绍 Java Module 系统的作用以及它如何使编写更安全、更结构化的代码受益。
使用 Java 模块的好处
使用模块化 Java 代码的一些好处如下:
强封装:全球空间中没有无意的类
Java 模块必须明确告知哪些 Java 包要导出(可用)到其他 Java 模块。这使得在模块级别实现了强大的封装。
减少编译时依赖性
当我们依赖于其他包时,Java 模块必须明确告诉需要哪些模块。这样可以节省时间,因为通过模块,JVM可以快速找到依赖项并加载它们。
更小的可部署资源
由于我们知道应用程序所需的所有依赖项,因此我们只能提供所需的包,从而导致应用程序的大小更小。
提高部署可靠性
通过模块定义指定依赖项,从开发时开始,所有依赖包都已经是已知的。这意味着在部署后,我们不会遇到由于缺少依赖项而发生运行时异常的问题。
如何定义模块
使用名为 module-info.java 的文件描述模块。模块定义包含以下信息:
模块名称
模块描述符
套餐集
依赖项、资源类型等。
在下一节中,我们将创建一个包含两个模块的 Java 模块化应用程序,这将为探索 Java 模块提供帮助,同时也为探索 Java 模块提供了一个良好的开端。
我们的模块化示例应用程序
我们将编写一个包含两个模块的小应用程序。
模块 1 (car.shop):第一个模块是汽车商店模块,它提供各种功能,如修理汽车、更换轮胎等。它取决于模块 2 提供的 DTO/Model 类。以下是 car.shop 模块的定义。
module car.shop {
exports car.shop;
requires car.common;
}
模块2(car.common):提供各种DTO类;以下是此模块的定义。
在这里,在这个模块中,我们将导出一个名为 car.common.model 的包。这意味着,即使这个特定的模块可能有很多包,我们也要确保这些包是封装的。只有我们认为应该对外开放的包裹才应该出口。
module car.common {
exports car.common.model;
}
示例代码
让我们看一下我们的示例服务类,该类在模块 1 中定义。
package car.shop;
import car.common.model.Car;
public class CarService {
public static void main(String[] args) {
Car car = new Car();
changeTire(car);
}
public static void changeTire(car.common.model.Car car) {
System.out.println("Car Service");
}
}
上面的代码看起来很熟悉,没什么特别的。我们正在定义一个静态方法 changeTire,它接受 car.common.model.Car 类型的参数。
现在这个特定的包 car.common.model 是在模块 2 中定义的,由于我们定义了两个模块,因此系统在编译时就知道我们有一个依赖项以及如何解决它。
到目前为止,它看起来不错,但有什么优势呢?
优点是我们在模块级别决定了包之间的关系。现在想象一下 car.common 包含许多其他包,如 car.internal、car.workin.progress、car.private.package 等;如果没有模块化 Java,就不可能只选择应用程序中所需的包,无论是否需要,我们都必须将所有包捆绑在一起。
使用 Java 模块,我们不仅可以封装需要对外部世界可用的包(export car.common),而且还可以确保不应该暴露的类或包对外界隐藏。
Java Module 项目的完整源代码可以在 GitHub 上找到。
总结
以模块化方式使用 Java 程序不是强制性的。尽管如此,它确实为开发人员提供了一种新工具,可以利用这个新概念来编写更高效(小尺寸)和安全(包级封装)的代码。