JEP 275:模块化 Java 应用程序打包
概括
将Project Jigsaw的功能集成到 Java Packager 中,包括模块感知和自定义运行时创建。
动机
由于 JRE 的大小,当Java Packager ( javapackager
) 被要求将运行时作为其打包的一部分进行捆绑时,它总是会生成巨大的二进制文件。Jigsaw 项目将开发 JEP 282 jlink 中定义的工具:Java 链接器,允许创建包含标准和 JDK 模块子集的运行时映像,使 Java Packager 能够减小捆绑的运行时映像的大小。
描述
在大多数情况下,Java Packager 工作流程将保持不变。将添加来自 Jigsaw 的新工具,并在某些情况下取代一些步骤。
仅生成 Java 9 应用程序
Java Packager 将仅创建使用 JDK 9 运行时的应用程序。这将简化许多关于用于组装应用程序和 Java 运行时的工 具的代码路径和假设。如果用户想要创建 Java 8 应用程序,那么 JDK 8 附带的 Java Packager 的 Java 8 版本将继续工作。我们假设需要在 Java 8 和 Java 9 上同时工作的独立应用程序的数量基本上为零,因为应用程序自带了自己的 JVM。
用于jlink
生成嵌入式 Java 运行时和应用程序映像
当前,JRE 已被复制,并且不需要的部分已从复制的运行时中删除。
Java 链接器工具提供了jlink
一种生成仅包含所需模块的 JRE 映像的方法。此外,jlink
可能会公开其图像生成过程的一些钩子,我们可以利用这些钩子来进一步自定义图像,例如,在处理jlink
或压缩中添加可执行文件的删除。
Java Packager 将调用jlink
创建应用程序运行时映像,该映像将嵌入到应用程序映像中。如果失败,Java Packager 将失败并出现相应的错误jlink
。预计打包的模块将随 JDK 9 一起提供。
该jlink
工具包括插件和扩展机制。当用于jlink
生成应用程序映像时,我们将与这些机制集成,以便进程的输出jlink
是采用正确的特定于平台的布局的应用程序映像。这将产生理想的副作用,使应用程序映像生成不依赖于 Java Packager 进程。
javapackager
CLI 参数、Ant 任务和 Java Packager API
Java Packager 具有新的 CLI 参数,以匹配 JEP 261 中指定的选项语法和值的 Java 工具链的其余部分:
--add-modules <module>(,<module>)*
--limit-modules <module>(,<module>)*
--module-path <path>(:<path>)*
-p <path>(:<path>)*
--module <module>/<classname>
-m <module>/<classname>
要为长选项指定参数,可以使用 --<名称>=<值> 或 --<名称> <值>。
注意:--module-path
映射到 jlink --module-path
,但具有可选的默认值。更多信息如下。
<fx:application>、<fx:secondaryLauncher> 和新的 <fx:runtime> 任务将有新的 ANT 任务。
例如:
<fx:deploy outdir="${bundles.dir}"
outfile="MinesweeperFX"
nativeBundles="all"
verbose="true">
<fx:runtime strip-native-commands="false"> <-- new
<fx:add-modules value="java.base"/>
<fx:add-modules value="jdk.packager.services,javafx.controls"/>
<fx:limit-modules value="java.sql"/>
<fx:limit-modules value="jdk.packager.services,javafx.controls"/>
<fx:module-path value="${java.home}/../images/jmods"/>
<fx:module-path value="${build.dir}/modules"/>
</fx:runtime>
<fx:application id="MinesweeperFX"
name="MinesweeperFX"
module="fx.minesweeper" <-- new
mainClass="minesweeper.Minesweeper"
version="1.0">
</fx:application>
<fx:secondaryLauncher name="Test2"
module="hello.world" <-- new
mainClass="com.greetings.HelloWorld">
</fx:secondaryLauncher>
</fx:deploy>
<fx:runtime>、<fx:limit-modules>、<fx:add-modules>、<fx:modular-path> 是可选参数。如果与模块化应用程序捆绑在一起,则使用 <fx:application> 上的 module="module name" 参数,否则如果应用程序是非模块化应用程序,则该参数无效。参数 <fx:limit-modules>、<fx:add-modules>、<fx:modular-path> 可与本文档中使用的 --add-mods、--limit-mods 和 --module-path 互换。有关附加模块的参数信息,请参阅模块配置部分。
Java Packager API 将获得模块化选项的新方法。
剥离本机命令
剥离 java.exe 等命令已成为 Java Packager 的默认设置,但一些开发人员需要 java.exe 等命令行工具。因此,将有一个选项通过关闭命令剥离的删除来包含本机命令:
--strip-native-commands false
添加对模块和模块路径的支持
除了类路径之外,Jigsaw 还引入了“模块路径”的概念。模块路径由库、JDK 模块和应用程序模块的路径组成。包含这些模块的路径是使用命令行参数指定的:
--module-path <path>(:<path>)*
它只能提供一次,并且是一个平台路径。根模块及其传递依赖项被链接以创建模块化运行时映像(JEP 220)。
开发人员可以提供包含打包模块的路径,以与默认版本之外的不同版本的 Java 运行时捆绑在一起。如果开发人员未提供 JDK 打包模块,则 Java 打包器将默认使用 Java 打包器附带的 JDK 版本 ($JAVA_HOME/jmods) 提供的打包模块。
Java Packager 目前不提供将打包模块复制到应用程序运行时映像而不是链接到jimage
.这种情况最可能的需要是应用程序支持插件并且这些模块位于捆绑映像之外。如果是这种情况,开发人员将需要使用用户 JVM 参数覆盖来覆盖 --module-path 和 --add-modules。
模块配置
使用 Java Packager 捆绑两种类型的 Java 应用程序:非模块化 JAR 和模块化应用程序。
非模块化 JAR 由 JAR 文件中不含 module-info.class 的 JAR 组成。使用-appClass
和-BmainJar=
.用于应用程序。开发人员将使用具有与 JDK 9 之前的版本相同的参数的 Java Packager,使用、-srcfiles
和-Bclasspath=
参数。为了向后兼容,不需要新的模块化参数,并且默认情况下嵌入式 Java 运行时将包含所有可再发行模块,因此捆绑运行时的大小不会减少。开发人员可以使用、和来包含第三方模块。-appClass``-BmainJar=``--module-path``--add-modules``--limit-modules
例如:
javapackager -deploy -v -outdir output -name HelloWorld -Bclasspath=hello.world.jar -native -BsignBundle=false -BappVersion=1.0 -Bmac.dmg.simple=true -srcfiles hello.world.jar -appClass HelloWorld -BmainJar=hello.world.jar
模块化应用程序由 JAR、分解模块或包含 module-info.class 的打包模块组成。 要与模块化应用程序捆绑在一起,必须指定--module
和参数。与互斥。必须提供包含主模块(用 引用的模块)的路径。其他模块可以添加到using和.通过核心反射或服务动态加载的模块必须使用 手动指定。主模块和 --add-modules 提供的模块将定义根模块。将使用指定的根模块及其传递依赖项创建运行时映像。--module-path``--module``-appClass``-BmainJar=``--module-path``--module``run-time image``--add-modules``--limit-modules``--add-modules``jlink
例如:
javapackager -deploy -v -outdir output -name Test -native -BsignBundle=false -BappVersion=1.0 -Bmac.dmg.simple=true --module-path /path/to/jmod --module hello.world/com.greetings.HelloWorld
该命令将生成一个由主模块及其所有传递依赖项组成的运行时映像。可以通过 --add-modules 选项添加其他模块。
模块
打包器将分为两个模块:
jdk.packager
jdk.packager.services
jdk.packager 包含构建应用程序包和安装程序的 Java Packager。 jdk.packager.services 是与应用程序包捆绑在一起的模块,可在运行时提供对打包程序服务(例如 JVM 用户参数)的访问。
自然语言处理
生成的捆绑包将取决于输入和提供的选项。历史上 -deploy 将生成所有本机捆绑包和 .jnlp 文件。现在,-deploy 与 -module 结合使用将不会生成 .jnlp 文件,因为 JNLP 不支持新的模块化选项。 -native 不带任何选项将生成所有可用的本机包。
测试
首先也是最重要的,在 JDK 8 中工作的 Java 打包器的现有 API、命令行和 Ant 调用应该在 JDK 9 中工作,因此应该运行 JDK 8 打包器的现有测试。
需要编写新的测试来执行新的标志,以支持run-time image
生成、模块路径规范和jeeps
进程交互。
风险和假设
我们假设该项目将基本上按照所描述的那样交付。如果大型功能部分被移至后续版本,例如模块路径和模块系统,那么该 JEP 的相应部分也会滑动。