JDK 17/21为何不再包含JRE及手动生成方法
1. JDK安装后为何缺少JRE文件夹
在JDK 17和21版本中,Oracle对Java的打包方式进行了重大调整。传统JDK安装包会同时包含开发工具(JDK)和运行时环境(JRE)两个独立目录,但从JDK 11开始,这种结构发生了变化。
1.1 模块化系统的引入
Java 9引入的模块化系统(Jigsaw项目)是这一变化的根本原因。模块化后,JRE不再是独立实体,而是作为JDK的一个子集存在。具体表现为:
- JDK镜像现在包含完整的Java SE规范实现
- 运行时环境(JRE)的功能已集成到JDK的jmods目录中
- 通过jlink工具可以按需创建自定义运行时镜像
1.2 实际目录结构对比
以Windows平台为例,传统JDK 8和现代JDK 17/21的目录结构差异明显:
JDK 8典型结构: ├── jdk1.8.0_291 │ ├── bin # 开发工具 │ ├── jre # 独立运行时 │ └── lib # 类库 └── jre1.8.0_291 # 独立安装的JRE JDK 17/21典型结构: ├── jdk-17.0.10 │ ├── bin # 开发工具 │ ├── conf # 配置文件 │ ├── include # 本地头文件 │ ├── jmods # 模块化组件 │ └── legal # 许可信息2. 手动生成JRE文件夹的三种方法
2.1 使用jlink工具创建精简运行时
这是Oracle官方推荐的方式,可以生成完全符合需求的JRE:
# 进入JDK安装目录 cd "C:\Program Files\Java\jdk-21.0.10" # 创建最小化JRE(约40MB) bin\jlink.exe --module-path jmods --add-modules java.base --output jre-minimal # 创建标准JRE(包含常用模块) bin\jlink.exe --module-path jmods \ --add-modules java.base,java.desktop,java.sql \ --output jre-standard关键参数说明:
--module-path:指定模块源路径--add-modules:选择要包含的模块--output:输出目录名称
2.2 通过安装程序生成传统JRE
虽然官方不推荐,但仍可通过以下步骤生成传统JRE:
- 以管理员身份打开命令提示符
- 执行以下命令:
cd "C:\Program Files\Java\jdk-21.0.10" bin\jlink.exe --module-path jmods --add-modules ALL-MODULE-PATH --output jre-full - 这会在JDK目录下创建完整的jre-full文件夹
2.3 复制法创建兼容性JRE(适用于老旧软件)
某些遗留系统可能严格要求传统JRE结构,可以这样处理:
# 创建基础目录结构 mkdir jre-legacy mkdir jre-legacy\bin mkdir jre-legacy\lib # 复制必要文件 xcopy /s /y bin\server jre-legacy\bin\server xcopy /s /y lib\* jre-legacy\lib\ copy bin\java.exe jre-legacy\bin\ copy bin\javaw.exe jre-legacy\bin\3. 环境变量配置的注意事项
3.1 标准配置方案
无论采用哪种JRE生成方式,环境变量都应指向JDK目录:
JAVA_HOME=C:\Program Files\Java\jdk-21.0.10 PATH=%JAVA_HOME%\bin;...3.2 特殊场景配置
如果某些应用必须使用独立JRE路径,可以这样设置:
# 使用jlink生成的JRE JRE_HOME=%JAVA_HOME%\jre-standard # 使用复制法生成的JRE JRE_HOME=%JAVA_HOME%\jre-legacy3.3 常见配置误区
- 路径冲突:避免同时配置JAVA_HOME和JRE_HOME指向不同版本
- 符号链接问题:Windows快捷方式不是真正的符号链接,建议使用完整路径
- 系统变量vs用户变量:开发环境建议配置系统变量
4. 验证与问题排查
4.1 基础验证步骤
# 验证Java版本 java -version # 验证编译器 javac -version # 检查模块系统 java --list-modules4.2 典型问题解决方案
问题1:找不到或无法加载主类
可能原因:
- 类路径未正确设置
- 模块路径冲突
解决方案:
# 明确指定类路径 java -cp bin;lib/* com.example.Main # 或指定模块路径 java -p mods -m module/package.Main问题2:jlink生成的JRE无法运行GUI程序
缺少必要模块:
# 重新生成包含GUI模块的JRE jlink --module-path jmods \ --add-modules java.desktop,java.base \ --output jre-with-gui问题3:与旧版JDK共存时的冲突
推荐处理方式:
- 卸载所有旧版Java
- 使用工具管理多版本:
# 使用jenv工具(需先安装) jenv add /path/to/jdk17 jenv add /path/to/jdk21 jenv global 21
5. 高级应用场景
5.1 创建平台专属运行时
针对特定硬件优化:
jlink --module-path jmods \ --add-modules java.base,java.desktop \ --output jre-arm64 \ --vm=server \ --strip-debug \ --no-header-files \ --no-man-pages5.2 构建Docker镜像优化
Dockerfile示例:
FROM eclipse-temurin:21-jdk-jammy AS builder RUN jlink --module-path $JAVA_HOME/jmods \ --add-modules java.base,java.logging \ --strip-debug \ --no-man-pages \ --output /opt/jre-minimal FROM ubuntu:22.04 COPY --from=builder /opt/jre-minimal /opt/jre ENV PATH="/opt/jre/bin:$PATH"5.3 性能调优建议
- 精简运行时大小:
jlink --compress=2 --no-header-files ... - 预生成类数据共享存档:
java -Xshare:dump -XX:+UseAppCDS - 选择适合的VM实现:
jlink --vm=client # 对GUI应用更友好 jlink --vm=server # 对服务端应用更优
对于需要兼容传统部署方式的场景,建议在持续集成流程中加入jlink步骤,自动生成符合要求的JRE分发包。现代Java应用更推荐直接使用JDK内置的运行时能力,而非维护独立的JRE副本。
