Java 平台模块系统入门第 1 部分
介绍
Java 9 将模块的概念引入 Java 平台。模块改变了我们设计和构建 Java 应用程序的方式。尽管模块的使用是可选的,但 JDK 本身现在已经模块化了,因此我们至少必须了解 Java 平台模块系统 (JPMS) 的基础知识。
在本指南系列中,您将了解什么是模块、它们解决哪些问题、如何创建模块、它们如何相互交互以及如何使用服务定位器模式解耦模块。在本系列的最后一篇指南中,我们将回顾 Maven 如何与模块系统配合使用。
我们将使用命令行来编译、打包和运行代码示例,以便更好地了解正在发生的事情。但是,您可以使用您最喜欢的 IDE 的最新(或测试版)版本来执行此操作。当然,您需要安装 Java 9 SDK。从此处或此处下载并按照安装说明进行操作。
我们先来谈谈什么是模块以及它们解决什么问题。
为何使用模块?
简而言之,模块(通常)是包含一组包的 JAR 文件。就像字段和方法分组到类中然后变成包一样,包也被分组到模块中。
模块化应用程序意味着将其分解为多个协同工作的模块。重要的是,使用模块时,您必须明确要求模块所依赖的其他模块,并且必须从模块中导出包以供其他模块使用。这带来了一些好处并解决了三个问题。
模块化解决的问题
首先,模块系统的直接后果是公共不再意味着每个人都可以访问某个类型。如果某个类被标记为公共,则它只能在模块内公开(如果其包未导出)或只能在需要它的特定模块内公开。
这促进了更强的封装(隐藏部分代码的能力),这很好,因为我们将不再能够访问我们不应该使用但偶尔会在版本之间发生变化并破坏我们的代码的内部(私有)类或私有成员(通过反射)。
然后,我们遇到了类加载器的问题。传统上,Java 虚拟机 (JVM) 使用类加载器来加载类路径中指定的类。但是,如果您忘记将 JAR 或类添加到类路径并运行应用程序,会发生什么情况?
可能什么都没有,这是一件坏事。是的,当类加载器尝试加载缺失的类时,将抛出ClassNotFoundException,但由于类是延迟加载的,因此这可能不会在应用程序启动时发生。
不要忘记,当我们有重复的 JAR 或两个库需要第三个库的不同版本时,可能会发生各种问题。这种情况甚至有个名字,叫JAR(或类路径)地狱。
像Maven(在编译时通过帮助管理依赖项)和开放服务网关计划(OSGi) (在运行时使用带元数据注释的 JAR,声明要从其他带注释的 JAR 中导出和导入哪些包)这样的项目可以帮助我们缓解这些类路径问题。
JPMS 并不打算完全取代这些项目(我们将在第 3 部分中特别讨论 Maven )。Java 现在拥有必要的信息,不仅可以在模块不存在或不可见时抛出编译时错误,而且在尝试启动应用程序而无法访问所需的所有模块或存在重复模块时,还可以抛出运行时错误。
第三个问题是 Java 应用程序的部署大小。即使是一个简单的Hello World程序,也需要完整的 JRE 安装,其中包含rt.jar文件(大约 50 MB),其中包含几乎所有的标准 Java 类。如前所述,除了为我们的应用程序提供模块系统外,JPMS 还将 JDK 本身模块化,借助工具jlink,我们可以创建仅包含所需模块的自定义 JDK。
此外,如果您的应用程序尚未准备好使用模块,也没有问题,模块的使用是可选的。Java 9 是向后兼容的,如果没有模块信息,Java 将照常使用类路径。此外,应用程序甚至可以混合使用模块路径和类路径。
解释了什么是模块以及它解决了什么问题之后,让我们深入创建我们的第一个模块。
我的第一个模块
作为示例,我们将使用一个类,其中的方法返回与编程相关的随机、预定义的引语:
import java.util.Random;
public class ProgrammingQuotes {
private String[] quotes = new String[] {
"\"To iterate is human, to recurse divine.\"\n" +
"- L. Peter Deutsch",
"\"Don't worry if it doesn't work right. If everything did, you'd be out of a job.\"\n" +
"- Mosher's Law of Software Engineering",
"\"Good design adds value faster than it adds cost.\"\n" +
"- Thomas C. Gale",
"\"Talk is cheap. Show me the code.\"\n" +
"- Linus Torvalds",
"\"I don't care if it works on your machine! We are not shipping your machine!\"\n" +
"- Vidiu Platon",
};
private Random rand = new Random();
private int getRandomIndex() {
return rand.nextInt(quotes.length);
}
public String getQuote() {
return quotes[getRandomIndex()];
}
public static void main(String args[]) {
System.out.println(new ProgrammingQuotes().getQuote());
}
}
首先,我们必须将我们的类放在包中,因为模块不能使用默认包(不能导出未命名的包)。
因此让我们使用包com.example.programming:
package com.example.programming;
import java.util.Random;
public class ProgrammingQuotes {
// ...
}
接下来,我们必须为模块选择一个名称。建议的方法是使用与包相同的反向域名模式。Oracle Java 平台组首席架构师 Mark Reinhold写道:
“强烈建议所有模块都按照反向 Internet 域名约定命名。模块的名称应与其主要导出 API 包的名称相对应,后者也应遵循该约定。如果模块没有这样的包,或者由于遗留原因,其名称必须与其导出的包之一不对应,则其名称至少应以与作者关联的 Internet 域名的反向形式开头。”
当然,你可以使用任何你想要的命名约定。例如,有些人使用简短的、面向项目的名称。
要创建模块,您需要在基础目录(包目录的起始位置)下添加module-info.java文件。按照惯例,此基础目录的名称与模块名称相同。
这样,我们的项目的目录结构应该是这样的:
|─ com.example.programming
| |─ module-info.java
| |─ com
| |─ example
| |─ programming
| |─ ProgrammingQuotes.java
在文件module-info.java中,您可以执行以下操作:
- 给你的模块命名
- 需要其他模块
- 从模块导出包
在这种情况下,它可以简单如下:
module com.example.programming {
}
现在打开一个终端窗口,确保cd进入基本目录,然后照常进行编译:
javac -d out module-info.java com/example/programming/ProgrammingQuotes.java
将创建目录out ,其中包含module-info.java和ProgrammingQuotes.java的已编译.class文件。
接下来,将类打包成模块化 JAR:
与普通 JAR 的唯一区别是存在module-info.class文件。
jar cvfe programming-quote.jar com.example.programming.ProgrammingQuotes -C out .
这将创建文件programming-quote.jar ,其中包括在目录out中找到的所有类,并以com.example.programming.ProgrammingQuotes作为主类。
现在运行它:
java -jar programming-quote.jar
当然,所有这些编译/打包/运行都可以通过 IDE 完成,但我想向您展示执行这些任务的命令并没有改变。
但是,要将该程序作为模块运行,必须使用选项--module-path(或仅使用-p )指定模块路径(包含模块,与包含类的类路径不同),并使用选项--module(或仅使用-m)指定主模块/类,格式为module/class:
java --module-path programming-quote.jar --module com.example.programming/com.example.programming.ProgrammingQuotes
或者,您可以使用包含编译类的out目录:
java --module-path out --module com.example.programming/com.example.programming.ProgrammingQuotes
但是,当您的应用程序有多个模块时,这些选项将成为上述命令的必需选项。
在下一篇指南《Java 平台模块系统入门第 2 部分》中,您将了解有关模块的更多信息以及如何使用ServiceLoader服务。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~