Java 9 平台级模块系统

模块化是 Java 9 一个非常重要的特性,终于有时间整理一下这方面的内容了。

模块化是软件工程中非常重要的一个概念。把独立的功能封装成模块,并提供接口供外部使用是我们在开发中努力实现的目标。模块化有很多好处:

  • 代码内聚,容易维护;
  • 能够有效降低复杂度;
  • 能提供更好的伸缩性和扩展性。

Java 9 的 Jigsaw 项目致力于为 Java 9 带来平台级的模块化系统。这个项目从 2008 年就已经开始,由于很多原因一直没有发布。现在,Jigsaw 涵盖了 6 个 JEP,终于作为 Java 9 的一部分发布出来。

从整体到模块

Java 一直坚持向后兼容,每更新一个版本,都变得更大更复杂。在过去的 JDK 版本中,没有强制要求模块化,使得 Java 平台和 JDK 越来越让人纠结。即便只是一个小小的 hello world,也需要加载几乎所有的 API。Jigsaw 项目致力于把 Java 平台和 JDK 分解成更小更有组织的模块。用户可以使用模块来构建软件,并且不需要包含所有的 API。

这项工作并不容易,Oracle 的 Java 平台组首席架构师 Mark Reinhold 曾经说过:

JDK代码库在API和实现级别上都是相互关联的,多年来主要以单片软件系统的方式构建。我们花了相当多的努力消除或至少简化了尽可能多的API和实现依赖关系,以便平台和它的实现可以作为一组相互依赖的模块来呈现,但是一些特别棘手的情况仍然存在。我们希望尽可能多地保持与先前版本的兼容性,特别是对于现有的基于类路径的应用程序,同时在可能的情况下,对于由模块组成的应用程序也是如此。

所有 Java 9 模块都在 $JAVA_HOME/jmods 目录下面。每个模块都具有暴露给其他模块的接口。这些模块互相依赖,并通过导出的包进行交互。 开发人员可以编译、打包、部署和执行仅由所选模块组成的应用程序,而无需其他任何操作。

如何使用模块

下面我们把自己的 Java 代码也进行模块化。新建两个简单的模块:

  • com.timeteller.clock:包含SpeakingClock的模块,用于将当前时间打印到stdout的简单类;
  • com.timeteller.main:使用com.timeteller.clock模块提供的功能的模块。

整个项目结构如下所示:

├── com.timeteller.clock
│   ├── com
│   │   └── timeteller
│   │       └── clock
│   │           └── SpeakingClock.java
│   └── module-info.java
└── com.timeteller.main
    ├── com
    │   └── timeteller
    │       └── main
    │           └── Main.java
    └── module-info.java

在 main 函数中调用方法与之前并无多少不同。

public static void main (String[] args) {
    SpeakingClock clock = new SpeakingClock();
    clock.tellTheTime(); // displays the time to stdout.
}

Java 9 平台级模块化系统最重要的部分在 module-info.java 中,这个文件定义了模块和元数据。内容如下所示。一个文件定义了 com.timeteller.clock 模块,并导出了 com.timeteller.clock 包;另一个文件定义了 com.timeteller.main 模块,并引用了 com.timeteller.clock 模块。

module com.timeteller.clock {
    exports com.timeteller.clock;
}
module com.timeteller.main {
    requires com.timeteller.clock;
}

module-info.java 的配置比较简单,可以看到:

  • 模块描述符文件放置在模块的根文件夹中;
  • 每个模块都有一个唯一的名称;
  • 模块描述符定义从模块导出的包以及它们需要哪些模块;

模块中的包如果没有导出,它的作用域就仅限于当前模块中,其他模块无法使用。这一特性使得 Java 9 中的 public 含义有所变化,模块中声明为 public 的类不再是可以随意访问的,只有导出以后才能从模块外访问到。基于这个特性,可以有效地隐藏模块内的 API。

编译 Java 程序

编译时可以这样打包:

$ mkdir -p jars
$ mkdir -p build/classes/com.timeteller.clock
$ javac -d build/classes/com.timeteller.clock/ com.timeteller.clock/module-info.java com.timeteller.clock/com/timeteller/clock/SpeakingClock.java
$ jar -c -f jars/clock.jar -C build/classes/com.timeteller.clock/ .
$ mkdir -p build/classes/com.timeteller.main
$ javac -d build/classes/com.timeteller.main/ --module-path=jars com.timeteller.main/module-info.java com.timeteller.main/com/timeteller/main/Main.java
$ jar -c -f jars/timeTeller.jar --main-class com.timeteller.main.Main -C build/classes/com.timeteller.main .

我们必须告诉编译器模块的路径(modulepath),编译器才能准确编译。模块路径的概念与 classpath 的概念非常相似。当我们构建 com.timeteller.main 模块时,需要在它的模块路径上放一个带有 com.timeteller.clock 的 jar。否则编译器找不到必需的代码并会导致编译错误:

$ javac -d build/classes/com.timeteller.main/ com.timeteller.main/module-info.java com.timeteller.main/com/timeteller/main/Main.java
com.timeteller.main/module-info.java:2: error: module not found: com.timeteller.clock
  requires com.timeteller.clock;

这里编译后创建的 jar 也是模块化,模块的 jar 与常规的 jar 基本一样,除了里面包括 module-info.class 文件。Java 9 即将到来,让我们一起期待吧。

分享学习笔记和技术总结,内容涉及 Java 进阶、架构设计、前沿技术、算法与数据结构、数据库、中间件等多个领域。关注作者第一时间获取最新内容,公众号同名(阅读体验更佳)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,442评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,604评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,576评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,652评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,495评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,370评论 1 274
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,792评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,435评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,735评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,777评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,553评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,399评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,806评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,038评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,330评论 1 253
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,766评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,964评论 2 337

推荐阅读更多精彩内容