从 rt.jar 到模块化:JDK9 类加载机制的全面演进
前言
从 JDK 9 开始,Java 引入了革命性的 模块系统(Java Platform Module System,JPMS)。它让整个 JDK 实现了彻底的模块化,也使类加载机制发生了根本变化。
新的目标是:
- 让 JDK 本身模块化(如 java.base、java.sql 等);
- 摆脱庞大的 rt.jar;
- 提升性能、封装性与可维护性。
为了理解这种变化,我们先从 JDK 8 的类加载机制讲起。
一、JDK8启动类加载器
概念
启动类加载器是最顶层的类加载器
- 是 由 C/C++ 实现的本地代码(Native Code);
- 不是真正意义上的 Java 对象(在 Java 层你拿不到它的实例);
- 主要负责加载 JRE 核心类库。
加载哪些内容
加载来源:$JAVA_HOME/jre/lib/rt.jar 和少量附属 JAR。
加载的典型包有:
| 类或包 | 说明 |
|---|---|
java.lang.* | 核心语言类(String、Object、Thread、Class 等) |
java.io.* | IO 基础类 |
java.net.* | 网络类 |
java.util.* | 集合、工具类 |
java.math.* | BigDecimal、BigInteger |
java.text.* | 文本处理 |
java.security.* | 安全相关类 |
javax.crypto.* | 加密 |
sun.* | 许多内部类(如 sun.misc.Unsafe) |
| ... | 基本所有标准核心 API |
这些都被打包在 rt.jar 和其他系统 jar(resources.jar, jsse.jar, charsets.jar)中。
可用命令查看:
java -XshowSettings:properties -version | grep boot.class.path

特点
| 特点 | 问题 |
|---|---|
所有核心类集中在 rt.jar | 文件巨大(60MB+),启动慢 |
| 统一加载所有核心类 | 无法按需加载或裁剪 |
| 依赖关系隐式存在 | 没有模块边界,依赖模糊 |
类加载路径通过 boot.class.path 配置 | 不支持模块化描述 |
二、JDK9的启动类加载器
JDK 9 的模块系统彻底重构了类加载架构。
不再使用 rt.jar,而是引入了新的 模块化加载体系,让每个模块自成单元、依赖明确。
JRT文件系统镜像
在 JDK 9 之前,所有核心类放在:
$JAVA_HOME/jre/lib/rt.jar而在 JDK 9 之后,这些类被打包成一个 特殊的二进制镜像文件:
$JAVA_HOME/lib/modules这个文件是一个 JRT(Java Runtime Image)文件系统镜像。
“JRT” 代表 “Java RunTime”
它不是 zip/jar,而是专门为 Java 设计的高效只读文件系统格式。
modules 文件中包含所有模块的 .class 文件:
可以用命令查看内容:
$JAVA_HOME/bin/jimage list $JAVA_HOME/lib/modules | head
(base) mumu@MacBook-Pro-21 ~ % $JAVA_HOME/bin/jimage list $JAVA_HOME/lib/modules | head
jimage: /Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home/lib/modulesModule: java.basejava/io/Bits.classjava/io/BufferedInputStream.classjava/io/BufferedOutputStream.classjava/io/BufferedReader$1.classjava/io/BufferedReader.classjava/io/BufferedWriter.classjava/io/ByteArrayInputStream.classjava/io/ByteArrayOutputStream.classjava/io/CharArrayReader.classjava/io/CharArrayWriter.classjava/io/CharConversionException.classjava/io/ClassCache$1.classjava/io/ClassCache$CacheRef.classjava/io/ClassCache.classjava/io/Closeable.class......- 每个模块对应一个“虚拟目录”(如
java.base/,java.sql/) - 每个目录里有模块内的 class 文件。
每个模块都有一个描述文件:系统在启动时,会根据这些描述文件建立 模块依赖关系图(Module Graph)。
// module-info.java
module java.sql {requires java.base;exports java.sql;
}
JVM如何读取这些文件
JVM 在启动时会挂载一个虚拟文件系统:
jrt:/你可以像访问文件系统一样访问模块中的类。
示例:
jrt:/java.base/java/lang/String.classJava 9+ 提供了一个标准 API 来访问它:
FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
Path path = fs.getPath("modules", "java.base", "java/lang/String.class");
System.out.println(Files.exists(path)); // true
为什么要用 JRT 镜像而不是 jar?
| 对比项 | rt.jar | modules(JRT 镜像) |
|---|---|---|
| 格式 | ZIP | 专用镜像格式 |
| 加载方式 | 传统类路径扫描 | 模块索引快速定位 |
| 扩展性 | 不支持模块依赖 | 支持模块化描述 |
| 启动性能 | 慢,需要解压索引 | 快,直接映射内存 |
| 定制能力 | 无法拆分 | 支持 jlink 打包精简 JRE |
JRT 镜像让 JVM 启动更快、内存占用更低,同时为模块化打下基础。
BuiltinClassLoader 与模块加载的关系
🧩 类加载器体系变化
JDK9 对类加载体系进行了重构:
| 类加载器 | JDK 8 实现 | JDK 9+ 实现 |
|---|---|---|
| 启动类加载器(Bootstrap) | C/C++ 实现 | BuiltinClassLoader 子类 |
| 扩展类加载器(Ext) | Launcher$ExtClassLoader | 平台类加载器(PlatformClassLoader) |
| 应用类加载器(App) | Launcher$AppClassLoader | BuiltinClassLoader 子类 |
🧩 BuiltinClassLoader 是什么?
BuiltinClassLoader 是 JDK9 新增的统一类加载器基类:
它负责:
- 从模块系统中查找类;
- 支持模块依赖与索引;
- 提供统一缓存与并发加载;
- 替代原先的
ExtClassLoader/AppClassLoader。
package jdk.internal.loader;
public class BuiltinClassLoader extends SecureClassLoader { ... }BuiltinClassLoader 如何从模块中加载类?
简化伪代码示例:
protected Class<?> findClass(String name) throws ClassNotFoundException {// 1. 通过模块系统查找模块Module module = moduleFinder.findModuleForClass(name);// 2. 通过 JRT 文件系统解析路径Path classFile = JRTFileSystem.resolve(module, name);// 3. 读取字节码并定义类byte[] bytes = Files.readAllBytes(classFile);return defineClass(name, bytes, 0, bytes.length);
}
JDK 内部通过 ClassPathImageReader 从 .jmod 或 .jimage 文件中直接读取字节码,
不再像之前那样扫描文件夹或解压 jar。
这大大提升了性能和加载安全性。
三、总结对比
| 项目 | JDK 8 | JDK 9+ |
|---|---|---|
| 核心类来源 | rt.jar | 模块镜像 $JAVA_HOME/lib/modules |
| 类加载实现 | 全由 native BootstrapClassLoader 完成 | BuiltinClassLoader 模块化实现 |
| 类加载路径 | sun.boot.class.path | 模块层(Module Layer) |
| 加载层级 | Bootstrap → Ext → App | Bootstrap → Platform → App |
| 模块化支持 | 无 | JPMS 模块系统 |
| 可裁剪性 | 无 | 支持 jlink 精简定制运行时 |
| 性能 | 启动慢、内存大 | 模块索引快速加载 |
| 核心加载类 | sun.misc.Launcher$ExtClassLoader | jdk.internal.loader.BuiltinClassLoader |
