双亲委派模型确保类唯一性和安全性,核心是“先委托父加载器、失败后再自加载”:类加载器收到请求后,先检查是否已加载,再递归委托至Bootstrap ClassLoader;若父级无法加载,才调用findClass从指定路径读取字节码并defineClass。

Java 类加载机制通过双亲委派模型(Parent Delegation Model)确保类的唯一性和安全性,核心是“先委托、再尝试、最后自加载”:每个类加载器在加载类前,先将请求委派给父加载器,只有当父加载器无法完成时,才由自己尝试加载字节码文件。
双亲委派的执行流程
当一个类加载器收到类加载请求时,它不会立即查找并加载字节码,而是按以下顺序处理:
- 检查该类是否已被当前加载器加载过(通过 defineClass 之后的 findLoadedClass 缓存判断);
- 若未加载,且存在父加载器,则调用父加载器的 loadClass 方法;
- 若父加载器为 null(即到达启动类加载器 Bootstrap ClassLoader),则由 JVM 内置逻辑加载
java.*等核心类; - 父加载器返回 null 或抛出 ClassNotFoundException 时,当前加载器才调用 findClass 方法,从指定路径(如 classpath、jar、网络等)读取字节码流,再通过 defineClass 转为 Class 对象。
关键加载器及其职责
标准 JDK 中有三类主要加载器,构成典型的父子链:
-
Bootstrap ClassLoader:由 C++ 实现,负责加载
$JAVA_HOME/jre/lib下的核心类(如java.lang.Object),无 Java 对应对象,getClassLoader() 返回 null; -
Extension ClassLoader:加载
$JAVA_HOME/jre/lib/ext或java.ext.dirs指定路径的扩展类; - Application ClassLoader(也称 System ClassLoader):加载 classpath 指定路径下的应用类,默认线程上下文类加载器(ContextClassLoader)。
开发者自定义类加载器通常继承 ClassLoader,并重写 findClass(而非 loadClass),以保持双亲委派语义。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
立即学习“Java免费学习笔记(深入)”;
为什么需要双亲委派?
主要解决两个关键问题:
- 避免重复加载:同一全限定名的类只会被一个加载器加载一次,保证类的唯一性(JVM 判定类相同需同时满足“类名 + 加载器实例”);
-
防止核心类被篡改:比如用户自定义一个
java.lang.String,由于双亲委派会优先由 Bootstrap 加载真实版本,自定义类根本不会被使用,保障了运行时安全。
打破双亲委派的典型场景
某些框架或容器需要绕过该模型,常见方式是重写 loadClass 方法,跳过父委托直接调用 findClass:
-
Tomcat:每个 Web 应用使用独立的 WebAppClassLoader,优先加载本应用
WEB-INF/classes和WEB-INF/lib中的类,实现应用间隔离; - OSGi / Spring Boot 的 DevTools:支持热替换和模块化,需动态卸载/重载类,必须突破默认委派链;
- 数据库驱动加载(DriverManager):JDBC 4.0 后依赖 SPI 机制,由线程上下文类加载器(通常是 AppClassLoader)加载第三方驱动,而非 Bootstrap。
注意:主动破坏双亲委派需谨慎,可能引发 LinkageError 或类冲突。

















