Java JVM 双亲委派(Parent Delegation)流程源码分析
本文将详细分析 Java 双亲委派机制(Parent Delegation Model) 的源码实现。为了全面理解,我会从原理、类加载器层级、关键源码方法、以及实际加载流程逐步讲解。
双亲委派时序流程图

一、双亲委派机制原理
双亲委派机制是 JVM 类加载器的一种设计模式:
-
每个类加载器都有一个父加载器(Parent)。
-
当一个类加载器接到类加载请求时:
- 先把请求交给父加载器。
- 如果父加载器能加载,则直接返回类。
- 如果父加载器不能加载,再由当前加载器尝试加载。
-
好处:
- 防止类重复加载。
- 保证核心 Java 类(如
java.lang.String)优先由 Bootstrap ClassLoader 加载,避免安全问题。
加载顺序可以概括为:

二、Java 类加载器层级
-
Bootstrap ClassLoader(启动类加载器)
- 用 C++ 写,加载
JDK核心类。 - 路径:
JAVA_HOME/jre/lib/rt.jar(JDK9 之后是模块化jrt:/)。
- 用 C++ 写,加载
-
Extension ClassLoader(扩展类加载器)
- Java 类:
sun.misc.Launcher$ExtClassLoader - 加载
JAVA_HOME/jre/lib/ext或系统属性java.ext.dirs下的 JAR。
- Java 类:
-
Application ClassLoader(系统类加载器)
- Java 类:
sun.misc.Launcher$AppClassLoader - 默认加载
classpath下的类。
- Java 类:
-
自定义 ClassLoader
- 可以继承
ClassLoader,实现自定义类加载逻辑。
- 可以继承
三、核心源码分析
关键类:java.lang.ClassLoader
1. loadClass 方法
源码(JDK8):
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// 1. 检查是否已经加载过
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
// 2. 委托给父加载器
if (parent != null) {
c = parent.loadClass(name, false);
} else {
// Bootstrap ClassLoader
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 父加载器找不到,当前加载器自己尝试
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
流程解析:
-
findLoadedClass(name)
- 检查类是否已经被加载过(缓存机制)。
-
父加载器委派
- 调用
parent.loadClass(name, false),父加载器先尝试加载。
- 调用
-
Bootstrap 加载器
- 如果父加载器为 null(即 bootstrap),直接调用
findBootstrapClassOrNull(name)。
- 如果父加载器为 null(即 bootstrap),直接调用
-
子加载器自己加载
- 父加载器无法加载时调用
findClass(name)。
- 父加载器无法加载时调用
-
resolveClass©
- 解析符号引用到直接引用。
2. findClass 方法
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
-
ClassLoader默认不实现实际加载逻辑。 -
子类(如 AppClassLoader) 会重写:
- 从文件系统或 jar 包中加载
.class文件。 - 调用
defineClass将字节码转换为Class对象。
- 从文件系统或 jar 包中加载
3. defineClass 方法
protected final Class<?> defineClass(String name, byte[] b, int off, int len)
throws ClassFormatError {
// 将字节码 b 转换为 Class 对象
}
- 作用:把字节数组形式的 class 文件定义为 JVM 中的类对象。
- 这是类加载器将二进制流真正变成
Class的关键方法。
四、完整加载流程示意
-
应用层调用:
Class.forName("com.example.MyClass") -
AppClassLoader.loadClass
- 调用父加载器
ExtClassLoader.loadClass ExtClassLoader再调用父加载器BootstrapClassLoader.loadClass
- 调用父加载器
-
Bootstrap 加载器加载
- 尝试加载
rt.jar中的核心类 - 成功则返回
- 失败则回退到子加载器
- 尝试加载
-
子加载器加载
- 调用
findClass从 classpath 或自定义路径加载
- 调用
-
返回
Class<?>对象
五、源码流程图(Mermaid)

六、源码重点总结
| 方法 | 功能 |
|---|---|
loadClass | 核心方法,实现双亲委派逻辑 |
findLoadedClass | 检查类是否已经加载过 |
findClass | 子类重写,真正实现类加载 |
defineClass | 将字节码转换成 JVM Class 对象 |
resolveClass | 链接类,解析符号引用 |
七、扩展
-
双亲委派打破方法
- 自定义类加载器直接覆盖
loadClass并不调用父加载器。 - 用于插件热加载、隔离不同版本的类。
- 自定义类加载器直接覆盖
-
注意事项
- Bootstrap 加载器无法直接在 Java 代码中引用。
- 双亲委派确保 Java 核心类不会被篡改。
本文来自博客园,作者:NeoLshu,转载请注明原文链接:https://www.cnblogs.com/neolshu/p/19120777

浙公网安备 33010602011771号