这篇文章主要针对Java库维护者。 任何这样的维护者都必须选择要定位的JDK:
l 针对最新的JDK(JDK 11或新发布的JDK 12),可为开发人员和用户提供最新API和更多功能的访问。
l 但是,它会阻止旧版JDK上的用户使用该库。
而那些较旧的JDK仍然非常受欢迎,在2018年占据约95%的份额,预计在2019年占据约90%。特别是JDK 8(> 80%份额)的普及使其成为现在的事实上的标准。
因此,后者正是许多图书馆维护者的决定性因素。 例如,vavr 1.0旨在以JDK 11为目标,但最终将以JDK 8为目标。
尽管如此,建议为JPMS添加一些支持,希望它将来能够被广泛采用。 Stephen Colebourne在这里描述了三个选项:
1. 什么都不做(不推荐)。
2. 最小值:在MANIFEST.MF文件中添加自动模块名称条目。
3. 最佳:添加针对JDK 9+的module-in,同时提供针对JDK 6-8 *的所有剩余类。
下面我们将深入研究如何实现选项三
注:我写的是关于JDK 6-8(而不是例如JDK 5-8),因为在JDK 11中,javac的--release选项限制在6-11范围内。
no1
为什么会选择JPMS呢? 主要是因为JPMS的以下三点特征:
1. 提供强大的封装
2. 防止引入拆分包
3. 确保更快的类加载
总而言之,JPMS非常酷,所以,我鼓励Java 6-8库的维护者充分利用JPMS:
l 对于他们自己,通过针对其模块的JDK 6-8类和其他模块编译module-in
l 对于他们的用户,通过提供module-in使库在模块路径上运行良好
no2
module-in的位置
module-in有两个位置:
1. 与所有其他类一样,在src / main / java中
2. 在单独的“源集”中,例如 在src / main / java9中。
我更喜欢选项1,因为它看起来更自然。
module-in的位置
module-in有两个地方可以结束:
1.在根输出目录中,包含所有其他类
2.在META-INF / versions / 9(Multi-Release JAR,AKA MRJAR)
no3
构建工具的示例库
本节包含一些库,这些库在定位JDK 6-8时提供module-in。
Ant
· Lombok (JDK 6 main + JDK 9 module-in)
Maven
· ThreeTen-extra (JDK 8 main + JDK 9 module-in)
· ·GoogleGson - 尚未发布(JDK 6 main + JDK 9 module-in)
· SLF4J - 尚未发布(META-INF / versions / 9中的JDK 6 main + JDK 9 module-in)
需注意的是,Maven Compiler Plugin提供了如何提供此类支持的示例。
Gradle
我没有找到任何使用Gradle提供此类支持的流行库(如果您知道,请发表评论)。 我只知道vavr尝试这样做
Gradle中的现有方法
ModiTect:ModiTect(由Gunnar Morling制作)及其Gradle插件(Serban Iordache)有一些非常酷的功能。 实质上,ModiTect在不使用javac的情况下生成module-in,基于特殊符号或直接来自module-in。
但是,在从module-in直接生成的情况下,ModiTect有效地复制了javac在引入自己的问题时所做的事情
这就是为什么我觉得这不是最好的工具。
Badass Jar插件:Serban Iordache还创建了一个Gradle插件,可以“无缝地创建模块化的jar,它们定位于9之前的Java版本”。
但是看起来很不错:
为了构建适当的JAR并验证module-in,Gradle构建必须运行两次,它不使用javac的--release选项,它保证只引用正确的API;它不使用javac来编译module-in。
JpmsGradlePlugin
这是我最近的发现:Axel Howind的JpmsGradlePlugin。
该插件做了一些不错的事情(例如,从javadoc任务中排除module-in),其特征如下:
l 它也不使用javac的--release选项,
l 它不完全支持Java模块化(例如模块修补),
l 它感觉不够成熟(代码难以理解,非标准行为,如直接调用javac)。
Gradle中提出的方法
Gradle脚本
最初,我想通过添加自定义源集来实现此目的。 然而,事实证明,这种方法会引入不必要的配置和任务,而我们真正需要的只是一个额外的任务,正确地“挂钩”到构建生命周期中。
结果,我想出了以下方法:
1.将compileJava配置为:excludemodule-in,
使用--release 6/7/8选项。
2.添加名为compileModuleInfoJava的新JavaCompile任务,并将其配置为:
仅包含module-in,
使用--release 9选项,
使用compileJava的类路径作为--module-path *,
使用compileJava *的目标目录
取决于oncompileJava *。
1.配置要依赖于compileModuleInfoJava的类任务。
这三个步骤是compileModuleInfoJava查看compileJava编译的类所必需的。 否则,由于未解析的引用,javac将无法编译module-in。 请注意,在这样的配置中,每个类只编译一次(与推荐的Maven编译器插件配置不同)。
Gradle Modules插件
(Gradle Modules Plugin)为Gradle添加了对JPMS的全面支持。
在这篇文章中,我展示了如何使用Gradle构建Java 6-8库,以便将module-in编译为JDK 9格式(JPMS支持),而所有其他类都编译为JDK 6-8格式。
我还建议使用Gradle Modules Plugin进行此类配置(只要我的PR合并并且新的插件版本被释放)。