jlink是Java 9+基于模块系统构建最小化运行时镜像最有效方式,通过精准裁剪未用JDK模块(如剔除java.desktop),结合jdeps分析依赖、--compress压缩及Docker多阶段构建,可将镜像体积压至50–80MB,且不改代码、不依赖外部工具。

直接用 jlink 构建最小化运行时镜像,是移除未用 JDK 模块、压减容器镜像体积最有效的方式。它不依赖外部工具链,也不修改应用代码,而是基于 Java 9+ 的模块系统,只打包真实需要的模块,从根源上剔除冗余。
确认应用实际依赖的 JDK 模块
盲目裁剪容易导致 NoClassDefFoundError 或 Module not found 错误。必须先做依赖分析:
- 若项目含
module-info.java,可直接用jdeps --list-deps your-app.jar查看显式依赖的模块(如java.base、java.logging) - 若为传统非模块化应用(无
module-info),用jdeps --multi-release 17 --print-module-deps your-app.jar推断隐式依赖(注意指定与构建环境一致的--multi-release版本) - 结合
--ignore-missing-deps和--verbose:class可定位运行时才加载的动态类所属模块,避免漏判
用 jlink 构建精简运行时镜像
拿到模块列表后,调用 jlink 合并 JDK 模块、应用代码与依赖库:
- 基础命令示例:
jlink --module-path $JAVA_HOME/jmods:libs --add-modules java.base,java.logging,java.xml --output myjre -
--module-path需包含 JDK 的jmods目录(路径因安装方式而异,常见为$JAVA_HOME/jmods)和你项目的第三方 jar(如libs/) - 加上
--compress=2可启用字节码压缩,进一步缩小体积;--no-header-files和--no-man-pages可剔除开发用文件 - 生成的
myjre/是一个完整可执行目录,内含bin/java,无需目标机预装 JRE
集成进 Docker 多阶段构建流程
把 jlink 步骤嵌入 Dockerfile,实现构建即瘦身:
- 第一阶段(builder):用完整 JDK 镜像(如
eclipse-temurin:17-jdk-jammy)编译代码、运行jlink,输出精简myjre/和应用 jar - 第二阶段(runtime):基于
scratch或debian:slim,仅COPY --from=builder复制myjre/和 jar,再ENTRYPOINT ["./myjre/bin/java", "-jar", "app.jar"] - 这样最终镜像不含任何编译工具、文档、调试器、冗余 locale 或 man 页面,体积通常控制在 50–80MB 区间
验证裁剪是否安全可靠
精简后务必覆盖关键场景测试,防止“省过头”:
- 启动时加
-Xlog:module*=info查看模块加载日志,确认无Skipping module或not found报错 - 运行时触发 JSON 解析、时间格式化、JDBC 连接等典型操作,验证
java.json、java.time、java.sql等模块是否按需包含 - 检查
myjre/bin/java --list-modules | grep -E '^(java|jdk)'输出,比对是否遗漏必要模块(例如java.desktop虽常用但多数服务端应用并不需要)

















