文章中如果有图看不到,可以点这里去 csdn 看看。从那边导过来的,文章太多,没法一篇篇修改好。

Java JVM 双亲委派(Parent Delegation)流程源码分析

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


双亲委派时序流程图

在这里插入图片描述

一、双亲委派机制原理

双亲委派机制是 JVM 类加载器的一种设计模式:

  1. 每个类加载器都有一个父加载器(Parent)。

  2. 当一个类加载器接到类加载请求时:

    1. 先把请求交给父加载器
    2. 如果父加载器能加载,则直接返回类。
    3. 如果父加载器不能加载,再由当前加载器尝试加载。
  3. 好处:

    • 防止类重复加载。
    • 保证核心 Java 类(如 java.lang.String)优先由 Bootstrap ClassLoader 加载,避免安全问题。

加载顺序可以概括为:

在这里插入图片描述


二、Java 类加载器层级

  1. Bootstrap ClassLoader(启动类加载器)

    • 用 C++ 写,加载 JDK 核心类。
    • 路径:JAVA_HOME/jre/lib/rt.jar(JDK9 之后是模块化 jrt:/)。
  2. Extension ClassLoader(扩展类加载器)

    • Java 类:sun.misc.Launcher$ExtClassLoader
    • 加载 JAVA_HOME/jre/lib/ext 或系统属性 java.ext.dirs 下的 JAR。
  3. Application ClassLoader(系统类加载器)

    • Java 类:sun.misc.Launcher$AppClassLoader
    • 默认加载 classpath 下的类。
  4. 自定义 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;
    }
}

流程解析:

  1. findLoadedClass(name)

    • 检查类是否已经被加载过(缓存机制)。
  2. 父加载器委派

    • 调用 parent.loadClass(name, false),父加载器先尝试加载。
  3. Bootstrap 加载器

    • 如果父加载器为 null(即 bootstrap),直接调用 findBootstrapClassOrNull(name)
  4. 子加载器自己加载

    • 父加载器无法加载时调用 findClass(name)
  5. resolveClass©

    • 解析符号引用到直接引用。

2. findClass 方法

protected Class<?> findClass(String name) throws ClassNotFoundException {
    throw new ClassNotFoundException(name);
}
  • ClassLoader 默认不实现实际加载逻辑。

  • 子类(如 AppClassLoader) 会重写:

    • 从文件系统或 jar 包中加载 .class 文件。
    • 调用 defineClass 将字节码转换为 Class 对象。

3. defineClass 方法

protected final Class<?> defineClass(String name, byte[] b, int off, int len)
        throws ClassFormatError {
    // 将字节码 b 转换为 Class 对象
}
  • 作用:把字节数组形式的 class 文件定义为 JVM 中的类对象。
  • 这是类加载器将二进制流真正变成 Class 的关键方法。

四、完整加载流程示意

  1. 应用层调用:Class.forName("com.example.MyClass")

  2. AppClassLoader.loadClass

    • 调用父加载器 ExtClassLoader.loadClass
    • ExtClassLoader 再调用父加载器 BootstrapClassLoader.loadClass
  3. Bootstrap 加载器加载

    • 尝试加载 rt.jar 中的核心类
    • 成功则返回
    • 失败则回退到子加载器
  4. 子加载器加载

    • 调用 findClass 从 classpath 或自定义路径加载
  5. 返回 Class<?> 对象


五、源码流程图(Mermaid)

在这里插入图片描述


六、源码重点总结

方法功能
loadClass核心方法,实现双亲委派逻辑
findLoadedClass检查类是否已经加载过
findClass子类重写,真正实现类加载
defineClass将字节码转换成 JVM Class 对象
resolveClass链接类,解析符号引用

七、扩展

  • 双亲委派打破方法

    • 自定义类加载器直接覆盖 loadClass 并不调用父加载器。
    • 用于插件热加载、隔离不同版本的类。
  • 注意事项

    • Bootstrap 加载器无法直接在 Java 代码中引用。
    • 双亲委派确保 Java 核心类不会被篡改。
posted @ 2025-09-01 11:02  NeoLshu  阅读(7)  评论(0)    收藏  举报  来源