从 JDK 9 开始,Oracle JDK 和 OpenJDK 不再默认包含独立的 JRE 目录,而是提供了 jlink
工具(Java 链接器),允许你根据需求自定义生成最小化的 JRE(包含必要的模块)。以下是使用 jlink
生成 JRE 的具体步骤:
生成 JRE 的步骤
1. 查看 JDK 包含的模块(可选)
首先,可通过 jdeps
或 java --list-modules
查看 JDK 中可用的模块,确定需要包含在 JRE 中的核心模块(如 java.base
是必选模块):
# 列出 JDK 所有模块
java --list-modules
包括一些基础模块:
java.base
:核心模块(String、集合、IO 等),所有 Java 程序都必须依赖,jlink
会自动包含(即使不显式指定)。java.logging
:日志基础支持(Spring 内部日志适配依赖)。java.sql
:若应用使用关系型数据库(如 MySQL、PostgreSQL),需保留(JDBC 依赖)。java.transaction
:事务管理支持(Spring 事务依赖javax.transaction
相关类)。java.xml
:XML 解析支持(Spring 配置文件、XML 格式处理依赖)。java.net.http
:若使用 JDK 内置 HTTP 客户端(如 Spring 的RestTemplate
底层可能间接用到)。java.management
:JMX 支持(Spring Boot Actuator 监控依赖)。jdk.unsupported
:部分第三方库(如 Netty)可能依赖其中的非标准 API(谨慎剔除)。
以下模块多用于桌面应用、废弃技术或特定场景,服务器端应用通常不需要:
模块名 | 用途 | 剔除理由 |
---|---|---|
java.desktop | 桌面 GUI(Swing、AWT 等) | Spring 是服务器端框架,无需 GUI 功能 |
java.scripting | 脚本引擎(如 Nashorn) | 不使用脚本动态执行逻辑时可剔除 |
java.rmi | 远程方法调用(RMI) | 现代 Spring 应用多用 REST/RPC,极少用 RMI |
java.corba | CORBA 协议支持(已废弃) | 早已被淘汰,Spring 无相关依赖 |
java.xml.ws | JAX-WS(SOAP 服务) | 若不开发 SOAP 服务,仅用 REST 可剔除 |
java.xml.bind | JAXB(XML 绑定) | 现代应用多用 JSON(Jackson),无需 XML 绑定 |
java.prefs | 偏好设置 API | 服务器端应用无需用户偏好配置 |
java.awt.headless | 无头模式(非 GUI 环境) | 虽与服务器相关,但 java.desktop 包含它,剔除 java.desktop 即可 |
jdk.jfr | 飞行记录器(性能监控) | 生产环境若不启用 JFR,可剔除 |
jdk.jconsole | 控制台监控工具 | 开发工具,生产 JRE 无需包含 |
jdk.jvisualvm | 可视化监控工具 | 同上,仅开发用 |
jdk.management.agent | JMX 代理 | 若不暴露远程 JMX 监控,可剔除 |
有写模块在特定场景下需要,需结合业务判断:
java.naming
:JNDI 支持(若应用部署在传统 Java EE 容器,可能需要;Spring Boot 独立部署可剔除)。java.security.jgss
:GSSAPI 安全认证(若不涉及 Kerberos 等复杂认证,可剔除)。java.net
:基础网络 API(核心模块依赖,无法单独剔除,但部分子功能可忽略)。jdk.net
:高级网络功能(如 HTTP/2),若应用仅用 HTTP/1.1 可剔除。
2. 使用 jlink
生成 JRE
基本命令格式:
jlink --module-path <模块路径> --add-modules <需要包含的模块> --output <生成的JRE目录>
--module-path
:指定模块路径,通常为 JDK 安装目录下的jmods
文件夹(如$JAVA_HOME/jmods
)。--add-modules
:指定需要包含的模块(多个模块用逗号分隔,java.base
是必须的)。--output
:指定生成的 JRE 存放目录(如./myjre
)。
高级选项(可选)
-
压缩 JRE 体积:使用
--compress
选项压缩模块(0
不压缩,1
常量字符串压缩,2
完全压缩):
jlink --module-path "$JAVA_HOME/jmods" --add-modules java.base --output myjre --compress 2
在较新的 JDK 版本(如 JDK 21+)中,jlink 的 --compress 参数确实已被标记为废弃(deprecated),并推荐使用更灵活的 --compress-level 参数替代。这一变化是为了统一压缩相关的参数命名和功能。
–compress-level 参数的功能与原 --compress 一致,但命名更清晰,支持的压缩级别范围相同(0-2):
–compress-level 0:不压缩(默认值)。
–compress-level 1:仅压缩常量池(字符串等),平衡体积和性能。
–compress-level 2:完全压缩(包括指令和常量池),体积最小但构建时间稍长。
-
排除调试信息:使用
--strip-debug
移除调试符号,减小体积:jlink --module-path "$JAVA_HOME/jmods" --add-modules java.base --output myjre --strip-debug
-
设置启动器:使用
--launcher
为应用创建自定义启动脚本:jlink --module-path "$JAVA_HOME/jmods" --add-modules java.base \--launcher myapp=java.base/com.example.MyMain \--output myjre
经验证,构建包含 20 个 modules 的 jre,大小约为 90M,zip 压缩后为 30M。
注意事项
- 模块依赖:
jlink
会自动包含指定模块的依赖模块(如添加java.desktop
会自动包含其依赖的java.base
、java.xml
等),无需手动添加所有依赖。 - 应用兼容性:生成 JRE 时需确保包含应用所需的所有模块,可通过
jdeps -s <你的应用.jar>
分析应用依赖的模块,再按需添加。 - 跨平台支持:
jlink
只能生成当前平台(如 Windows x64)的 JRE,跨平台生成需在对应平台的 JDK 中执行命令。
通过 jlink
生成的 JRE 是轻量且定制化的,仅包含必要的模块,适合在生产环境中部署,减少资源占用。