1. JDK 17与JRE的关系演变
在Java 9之前,JDK和JRE是两个独立的安装包。JRE(Java Runtime Environment)作为Java程序的运行环境,包含了JVM核心和基础类库。但从Java 9开始,随着模块化系统的引入,Oracle调整了发布策略——JDK 17不再提供独立的JRE安装包,而是通过jlink工具按需生成定制化的运行时镜像。
这种变化源于几个关键考量:
- 空间效率:传统JRE包含所有模块,而实际应用可能只用其中20%的内容
- 安全维护:精简运行时环境能减少潜在攻击面
- 部署灵活:开发者可以精确控制目标环境包含的模块
重要提示:从JDK 11开始,Oracle官方不再提供独立的JRE下载。所有运行时环境的创建都需要通过JDK中的工具链完成。
2. 准备jlink工具环境
2.1 验证JDK 17安装
在开始制作前,需要确认系统已安装JDK 17并配置好环境变量。在命令行执行:
bash复制java -version
正常输出应类似:
code复制openjdk version "17.0.3" 2022-04-19
OpenJDK Runtime Environment (build 17.0.3+7-Debian-1deb11u1)
OpenJDK 64-Bit Server VM (build 17.0.3+7-Debian-1deb11u1, mixed mode)
2.2 了解模块系统
JDK 17采用模块化设计,所有功能被划分为标准模块。查看完整模块列表:
bash复制java --list-modules
典型输出示例:
code复制java.base@17.0.3
java.compiler@17.0.3
java.datatransfer@17.0.3
...
3. 基础JRE镜像制作
3.1 最小化运行时创建
创建一个仅包含java.base模块的最小JRE:
bash复制jlink --add-modules java.base --output jre-minimal
参数说明:
--add-modules:指定要包含的模块--output:输出目录名称
生成后的目录结构:
code复制jre-minimal/
├── bin
│ ├── java
│ └── keytool
├── conf
├── include
├── legal
└── lib
3.2 典型桌面应用配置
对于需要图形界面的应用程序,需添加更多模块:
bash复制jlink --add-modules java.desktop,java.sql --output jre-desktop
推荐包含的常用模块组合:
- 基础功能:
java.base,java.logging,java.xml - 网络应用:
java.net.http,java.naming - 图形界面:
java.desktop,java.datatransfer
4. 高级定制技巧
4.1 模块依赖分析
使用jdeps工具分析应用依赖:
bash复制jdeps -s your-application.jar
输出示例:
code复制your-application.jar -> java.base
your-application.jar -> java.desktop
your-application.jar -> java.sql
4.2 包含服务提供者
当应用使用SPI机制时,需要显式添加服务提供者:
bash复制jlink --add-modules java.base,java.logging \
--suggest-providers java.util.logging.LoggingProvider
4.3 裁剪本地库
减少平台相关库的体积:
bash复制jlink --add-modules java.base \
--strip-debug \
--no-header-files \
--no-man-pages \
--output jre-stripped
5. 优化与调试配置
5.1 启动参数优化
在conf/目录下创建配置文件:
properties复制# conf/management/management.properties
com.sun.management.jmxremote.port=7091
com.sun.management.jmxremote.authenticate=false
com.sun.management.jmxremote.ssl=false
5.2 生成调试符号
保留调试信息用于问题诊断:
bash复制jlink --add-modules java.base \
--compress=1 \
--strip-debug=false \
--output jre-with-debug
5.3 多平台兼容处理
针对不同操作系统创建运行时:
bash复制# Windows
jlink --add-modules java.base --output jre-win --module-path "%JAVA_HOME%\jmods"
# Linux
jlink --add-modules java.base --output jre-linux --module-path "$JAVA_HOME/jmods"
6. 实际应用验证
6.1 测试JRE可用性
使用生成的JRE运行测试程序:
bash复制./jre-custom/bin/java -jar your-app.jar
6.2 体积对比分析
典型场景下的JRE大小比较:
| 配置方案 | 大小(MB) | 包含模块 |
|---|---|---|
| 完整JRE | 200+ | 所有标准模块 |
| 最小化配置 | 35 | java.base |
| 典型桌面配置 | 85 | java.base+java.desktop+java.xml |
| 企业级Web应用配置 | 120 | java.base+java.sql+java.net.http |
7. 持续集成方案
7.1 Maven集成配置
在pom.xml中添加jlink插件:
xml复制<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jlink-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<jlinkArgs>
<jlinkArg>--strip-debug</jlinkArg>
<jlinkArg>--no-man-pages</jlinkArg>
</jlinkArgs>
<modules>
<module>java.base</module>
<module>java.desktop</module>
</modules>
</configuration>
</plugin>
7.2 自动化构建脚本
示例Gradle配置:
groovy复制plugins {
id 'org.beryx.jlink' version '2.25.0'
}
jlink {
options = ['--strip-debug', '--compress', '2']
addModules = ['java.desktop', 'java.sql']
}
8. 常见问题解决方案
问题1:缺失模块导致ClassNotFound
bash复制Error: Module not found: java.sql
解决方案:
- 重新运行jlink添加缺失模块
- 使用
jdeps全面分析依赖
问题2:服务提供者未加载
bash复制ServiceConfigurationError: Provider not found
解决方案:
- 添加
--suggest-providers参数 - 确保META-INF/services配置正确
问题3:跨平台兼容性问题
bash复制UnsupportedClassVersionError
解决方案:
- 确保生成环境与目标环境版本一致
- 使用
--target-platform指定目标平台
经过多次实践验证,我发现最稳妥的做法是先在开发环境生成测试JRE,通过完整测试后再部署到生产环境。对于企业级应用,建议保留10%-20%的额外模块余量以应对未来需求变化。
