ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

JDK jlink 完全指南:组装并优化自定义运行时镜像

JDK jlink 完全指南:组装并优化自定义运行时镜像 JDK jlink 完全指南组装并优化自定义运行时镜像【免费下载链接】jdkJDK main-line development https://openjdk.org/projects/jdk项目地址: https://gitcode.com/GitHub_Trending/jd/jdk本篇指南围绕 OpenJDK 官方 man 页 jlink.md 展开完整覆盖jlink的定位、命令行选项、插件体系与实战示例并结合src/jdk.jlink模块的真实源码任务参数解析、插件注册机制说明其底层工作原理。读完后你将能够熟练使用jlink把指定的模块及其传递依赖链接成精简的自定义运行时镜像掌握压缩、去调试符号、限定 locale、裁剪证书等常用优化手段并理解选项背后的源码实现路径。一、jlink 是什么从官方 Name 与 Description 说起jlink的官方一句话定义是jlink - assemble and optimize a set of modules and their dependencies into a custom runtime imagejlink —— 将一组模块及其依赖组装并优化为自定义运行时镜像Description 部分进一步说明jlink工具将一组模块**连同它们的传递依赖transitive dependencies**链接起来创建一个自定义运行时图像custom runtime image。这里有一个官方特别提醒值得强调Note:Developers are responsible for updating their custom runtime images. 开发者有责任自行更新其自定义运行时镜像。也就是说自定义运行时镜像不会随 JDK 自动升级。当你更新了 JDK 或应用模块后需要重新执行jlink生成新的镜像。这也是理解 jlink 工作模式的关键它是链接时裁剪工具——模块解析、资源收集、图像布局都在这一次性命令中完成产物是一个自包含、可独立分发的目录。二、命令概要Synopsis官方给出的标准调用形式为jlink [options] --module-path modulepath --add-modules module[,module...]各要素的含义options以空格分隔的命令行选项完整列表见下文jlink 命令行选项一节modulepathjlink在此路径上发现可观测模块observable modules。这些模块可以是**模块化 JAR 文件、JMOD 文件或展开的模块目录exploded modules**三种形式之一module要加入运行时镜像的模块名。jlink会添加这些模块并自动带上它们的传递依赖。从源码结构看这个概要三要素在实现中对应JlinkTask的核心选项定义。JlinkTask.java 在构造器中通过addOption(...)注册了--limit-modules、--bind-services、--suggest-providers等选项而帮助文本含本 man 页中出现的描述则集中在 jlink.properties 中按main.opt.*键维护例如其中main.opt.limit-modules与err.limit.modules‑‑limit-modules not allowed with ‑‑add-modules ALL-MODULE-PATH分别对应选项说明和错误提示。三、jlink 命令行选项全集以下按 man 页逐项继承并结合源码补充说明。3.1 模块与依赖类选项--add-modules mod[,mod...]把指定模块添加到默认根模块集合中。默认根模块集合为空。镜像中实际包含的模块 根模块 其传递闭包。-p或--module-path modulepath指定模块路径。man 页给出了三条重要默认行为若未指定默认模块路径为$JAVA_HOME/jmods该目录包含java.base及其他标准模块与 JDK 模块若指定了模块路径但从中无法解析出java.basejlink会自动把$JAVA_HOME/jmods追加到模块路径末尾保证核心模块始终可用模块可以是模块化 JAR、JMOD 或展开模块目录。--limit-modules mod[,mod...]将可观测模块的宇宙限定为指定模块的传递闭包 主模块如有--add-modules进一步指定的模块。它的作用是让jlink只看见你关心的模块缩小解析范围。源码中这一限制有明确的互斥校验JlinkTask.java 第 447 行附近的注释与 jlink.properties 中的err.limit.modules表明--limit-modules不允许与--add-modules ALL-MODULE-PATH同时使用二者语义直接冲突。--bind-services链接服务提供者service provider模块及其依赖。对应java.lang.module.Configuration.resolveAndBind(ModuleFinder, List, ModuleFinder, Collection)方法的语义先解析根模块再把实现了所需服务的提供者模块及其依赖一并拉入图像。--suggest-providers [name,...]从模块路径中建议实现了给定服务类型service type的提供者只建议、不链接。man 页给出的示例见第五节展示了如何用它发现java.security.Provider的实现者。源码中若指定服务未找到提供者会输出 jlink.properties 中定义的warn.provider.notfound警告。3.2 输出与产物类选项--output path指定生成的运行时镜像位置输出目录。--endian {little|big}指定生成镜像的字节序默认值是当前系统架构的格式。-c zip-{0-9}或--compresszip-{0-9}启用资源压缩。取值zip-{0-9}zip-0不压缩zip-9压缩率最高默认是zip-6。同时列出将在未来版本移除的弃用值0不压缩应改用zip-01常量字符串共享constant string sharing2ZIP 压缩应改用zip-6。--ignore-signing-information当签名的模块化 JAR 被链接进运行时镜像时抑制致命错误签名的模块化 JAR 中签名相关文件不会被复制到运行时镜像。--launcher commandmodule或--launcher commandmodule/main为模块指定启动器命令名当同时给出主类时模块名与主类名用斜杠/分隔。这样生成的镜像bin目录下会出现名为command的可执行文件直接启动module的可选指定main主类。--no-header-files排除头文件C header files。--no-man-pages排除 man 页。这两个选项适合需要进一步瘦身、且不使用 JNI/原生开发或 man 场景的部署。3.3 调试、信息与杂项选项--disable-plugin pluginname禁用指定插件可用插件清单见下文插件章节及jlink --list-plugins。--list-plugins列出所有可通过命令行选项访问的可用插件。-h/--help打印帮助信息。--version打印版本信息。--save-opts filename把本次jlink使用的选项保存到指定文件便于复核与复现。3.4 选项文件filenamefilename从文件读取选项。选项文件规则是一个包含通常在命令行输入的选项和值的文本文件选项可以写在一行也可以跨多行不能在路径名中使用环境变量以井号#开头的行视为注释。man 页给出的选项文件示例#Wed Dec 07 00:40:19 EST 2016 --module-path mlib --add-modules com.greetings --output greetingsapp配合--save-opts可形成生成 → 保存 → 复现的完整工作流。四、jlink 插件体系Plug-insman 页对插件有两点前置说明务必注意Note:Plug-ins not listed in this section arent supported and are subject to change. 本小节未列出的插件不受支持且随时可能变化。对于需要pattern-list模式列表参数的插件选项取值是逗号分隔的元素列表每个元素可取以下四种形式之一glob-pattern裸 glob 模式glob:glob-patternregex:regex-patternfilename—— 文件名其中每行一个模式查看完整插件列表的命令jlink --list-plugins4.1 插件compress选项--compresszip-{0-9}[:filterpattern-list]作用压缩输出图像中的所有资源。取值zip-{0-9}zip-0不压缩zip-9压缩率最高默认zip-6。弃用值未来版本移除Level 0不压缩改用zip-0、Level 1常量字符串共享、Level 2ZIP改用zip-6。可选的pattern-list过滤器用于列出要包含压缩的文件模式。从源码结构看压缩逻辑由 ZipPlugin.java 与 DefaultCompressPlugin.java 实现字符串共享的旧路径则对应 StringSharingPlugin.java。4.2 插件include-locales选项--include-localeslangtag[,langtag]\*作用只包含指定语言标签BCP 47 langtag对应的 locale 资源locale 匹配遵循 RFC 4647 定义。前提使用本选项时必须加上jdk.localedata模块。示例--add-modules jdk.localedata --include-localesen,ja,*-IN对应实现见 IncludeLocalesPlugin.java。4.3 插件order-resources选项--order-resourcespattern-list作用按优先级顺序排列指定路径。若指定了filename则pattern-list中每一行必须与待排序路径精确匹配。示例--order-resources/module-info.class,classlist,/java.base/java/lang/对应实现见 OrderResourcesPlugin.java。该插件影响 JRT 归档内资源的物理排列顺序对镜像内的资源查找与缓存友好性有实际意义。4.4 插件strip-debug选项--strip-debug作用去除输出镜像中的调试信息。从源码结构看--strip-debug组合了两个处理StripJavaDebugAttributesPlugin.java 处理类文件中的调试属性DefaultStripDebugPlugin.java 作为默认的 strip-debug 插件入口后者同时承担对原生调试符号的处理策略。4.5 插件generate-cds-archive选项--generate-cds-archive作用若运行时镜像支持 CDS 特性则为其生成 CDSClass Data Sharing归档以加速 JVM 启动与类加载。对应实现见 CDSPlugin.java。4.6 插件cacerts选项--cacertsalias[,alias]\*作用在输出镜像中创建cacerts密钥库但只保留指定别名对应的证书。alias是java.base模块中cacerts密钥库里的别名。对应实现见 CACertsPlugin.java。这是安全场景下裁剪信任根的官方手段仅保留业务实际依赖的 CA 证书。4.7 插件的底层机制ServiceLoaderman 页只描述插件的使用面而发现面可以追溯到源码PluginRepository.java 通过ServiceLoader.load(pluginsLayer, Plugin.class)从模块层加载插件实现newPlugin(config, name, pluginsLayer)负责按名称取插件并调用configure(config)完成配置若同一名称出现多个提供者则抛出PluginException。这也解释了为什么--disable-plugin能精确关闭某个插件——插件名是唯一键。插件实现的源码集中于 plugins 目录如ExcludeVMPlugin、GenerateJLIClassesPlugin、ReleaseInfoPlugin等未在 man 页列出的插件正对应未列出即不受支持的说明。而 Jlink.java 提供了编程式调用入口Jlink.newPlugin(name, configuration, pluginsLayer)以及Jlink.JlinkConfiguration输出目录、根模块集合、ModuleFinder、是否从运行时镜像链接、是否生成运行时镜像等与PluginsConfiguration插件列表、ImageBuilder、最后一个排序插件名——排序插件之后不再允许重新排序说明jlink的命令行能力本质上可被 API 完整复现。五、jlink 实战示例完整继承 man 页5.1 创建最简运行时镜像以下命令在greetingsapp目录创建一个运行时镜像链接模块com.greetings其模块定义位于mlib目录jlink --module-path mlib --add-modules com.greetings --output greetingsapp列出该镜像中的模块greetingsapp/bin/java --list-modules com.greetings java.base11 java.logging11 org.astro1.0可以看到最终镜像只包含com.greetings及其依赖java.base、java.logging与com.greetings依赖的org.astro而不是整个 JDK。5.2 压缩 去调试符号 限定 locale以下命令创建目录compressedrt中的运行时镜像去除调试符号、使用压缩减小体积、只包含法语 locale 信息jlink --add-modules jdk.localedata --strip-debug --compress2 --include-localesfr --output compressedrt再创建一个未去调试符号、未压缩的对照镜像fr_rt并对比大小jlink --add-modules jdk.localedata --include-localesfr --output fr_rt du -sh ./compressedrt ./fr_rt 23M ./compressedrt 36M ./fr_rtman 页给出的这组对比数据说明仅去调试符号 压缩两项优化就把镜像从 36M 降到 23M。注意示例中沿用了弃用值--compress2按前文选项说明新脚本中建议改写为--compresszip-6。5.3 用--suggest-providers发现安全提供者以下示例列出实现java.security.Provider的提供者jlink --suggest-providers java.security.Provider Suggested providers: java.naming provides java.security.Provider used by java.base java.security.jgss provides java.security.Provider used by java.base java.security.sasl provides java.security.Provider used by java.base java.smartcardio provides java.security.Provider used by java.base java.xml.crypto provides java.security.Provider used by java.base jdk.crypto.cryptoki provides java.security.Provider used by java.base jdk.security.jgss provides java.security.Provider used by java.base这一步的价值在于先只读地摸清服务依赖面再决定最终镜像要链接哪些模块避免盲目裁剪导致运行时ServiceLoader失效。5.4 只链接指定的提供者精确裁剪以下示例创建名为mybuild的自定义运行时镜像只包含java.naming与jdk.crypto.cryptoki及其依赖而不包含其他提供者。注意这些依赖必须存在于模块路径中jlink --add-modules java.naming,jdk.crypto.cryptoki --output mybuild5.5 用--bind-services链接服务绑定后的模块集以下命令与创建greetingsapp的命令类似区别在于链接从根模块经服务绑定service binding解析出的模块语义对应Configuration.resolveAndBind方法jlink --module-path mlib --add-modules com.greetings --output greetingsapp --bind-services用该命令创建greetingsapp镜像后列出模块man 页原样输出greetingsapp/bin/java --list-modules com.greetings java.base11 java.compiler11 java.datatransfer11 java.desktop11 java.logging11 java.management11 java.management.rmi11 java.naming11 java.prefs11 java.rmi11 java.security.jgss11 java.security.sasl11 java.smartcardio11 java.xml11 java.xml.crypto11 jdk.accessibility11 jdk.charsets11 jdk.compiler11 jdk.crypto.cryptoki11 jdk.crypto.ec11 jdk.crypto.mscapi11 jdk.internal.opt11 jdk.jartool11 jdk.javadoc11 jdk.jdeps11 jdk.jfr11 jdk.jlink11 jdk.localedata11 jdk.management11 jdk.management.jfr11 jdk.naming.dns11 jdk.naming.rmi11 jdk.security.auth11 jdk.security.jgss11 jdk.zipfs11 org.astro1.0对比 5.1 节未加--bind-services时仅 4 个模块的结果服务绑定会把所有为根模块提供所需服务的提供者模块连同其依赖一并拉入如java.desktop、jdk.jfr、jdk.crypto.ec等这正是resolveAndBind的行为——它保证任何服务调用都能被解析到具体实现。因此只要你的代码依赖 SPIServiceLoader就应该评估--bind-services或使用--suggest-providers显式确认提供者集合否则运行时可能出现服务找不到实现的问题。六、常见组合与适用前提小结把上述选项按目的归类便于实际选用目标典型选项组合最小可用镜像--module-path--add-modules--output进一步瘦身--strip-debug--compresszip-6--include-locales需jdk.localedata排除原生开发资源--no-header-files--no-man-pages安全信任根裁剪--cacertsalias,...服务治理--suggest-providers先诊断--bind-services或显式--add-modules再定稿启动器封装--launcher appmod/Main加速启动--generate-cds-archive镜像需支持 CDS适用前提与限制以当前仓库文档为准jlink发现模块的路径默认为$JAVA_HOME/jmods显式指定--module-path后若解析不到java.base会自动回退追加默认路径未列于插件章节的插件不受支持、可能随时变化--compress的数值型旧值0/1/2已弃用应使用zip-0…zip-9形式自定义运行时镜像不会自动更新JDK 或模块变更后需重新执行jlink--limit-modules与--add-modules ALL-MODULE-PATH互斥见 jlink.properties 中的err.limit.modules。七、延伸阅读jlink 的源码入口命令入口与选项注册JlinkTask.java--limit-modules、--bind-services、--suggest-providers等均在此定义与校验编程式 APIJlink.javaJlinkConfiguration/PluginsConfiguration/newPlugin插件发现与配置PluginRepository.java插件实现目录internal/pluginsZipPlugin、IncludeLocalesPlugin、OrderResourcesPlugin、CDSPlugin、CACertsPlugin等帮助与错误文案国际化资源jlink.properties同目录的姊妹工具文档jmod.mdjlink的常见输入源 JMOD 由其生成【免费下载链接】jdkJDK main-line development https://openjdk.org/projects/jdk项目地址: https://gitcode.com/GitHub_Trending/jd/jdk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表