双亲委派模型是类加载器优先委托父加载器加载类,父无法加载时才自行加载,形成自下而上的责任链,旨在保障类的唯一性、安全性与一致性。

双亲委派模型不是“父母双方一起委托”,而是指类加载器收到加载请求时,**优先向上委托给父加载器处理,仅当父加载器无法加载时,才由自己尝试加载**。它本质是一条自下而上的责任链,核心目标是解决类的唯一性、安全性和一致性问题。
类加载器的层级关系要理清
Java 中默认有三层(JDK9+为四层)逻辑层级,注意这不是 Java 继承关系,而是构造时显式指定的 parent 引用:
-
Bootstrap ClassLoader:C++ 实现,加载
$JAVA_HOME/jre/lib下的核心类(如java.lang.Object),Java 层不可见(表现为null) -
Platform ClassLoader(JDK9+ 替代 ExtensionClassLoader):加载平台模块(如
java.sql),父为 Bootstrap - Application ClassLoader:也叫系统类加载器,加载 classpath 下的用户类,父为 Platform
-
自定义 ClassLoader:继承
ClassLoader,默认父为 Application ClassLoader
loadClass() 方法才是关键实现
真正执行双亲委派的是 ClassLoader.loadClass(String, boolean) 的默认逻辑,分三步:
- 先查缓存:
findLoadedClass(name)—— 已加载直接返回,避免重复 - 再向上委派:
parent.loadClass()(若 parent 为 null,则调用findBootstrapClassOrNull()) - 最后自救:
c == null时调用findClass(name),该方法为空,必须由子类重写来读取字节码
⚠️ 注意:findClass() 不做委派,只负责“找字节码”;defineClass() 才把字节码转成 Class 对象。漏掉 defineClass() 会报 NoClassDefFoundError。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
为什么必须有这个机制?三个现实痛点
不走双亲委派,JVM 就会立刻出问题:
-
安全崩塌:你写个
java.lang.String放进 classpath,若 AppClassLoader 直接加载,就覆盖了 JVM 自带的 String,所有基础行为(equals、hashCode)都可能被篡改 -
ClassCastException 频发:Tomcat 两个 WebApp 各自用不同加载器加载同一个
StringUtils,JVM 视为两个无关类,哪怕字节码一模一样,转型也会失败 -
内存浪费 + 初始化混乱:每个加载器都重复加载
ArrayList,元空间堆满相同类,静态代码块还可能执行多次
哪些场景需要打破它?怎么破?
打破不是为了炫技,而是解决实际隔离或动态性需求:
-
Web 容器(如 Tomcat):每个 WebApp 需要独立加载自己的
lib和类,且优先用自己的版本(如不同版本的 Spring),所以 WebAppClassLoader 先尝试自己加载,找不到再委派——需重写loadClass() -
SPI 机制(如 JDBC):
DriverManager由 Bootstrap 加载,但具体驱动(com.mysql.cj.jdbc.Driver)在应用 jar 包里,Bootstrap 找不到。于是用线程上下文类加载器(Thread.currentThread().getContextClassLoader())反向委托给 AppClassLoader 加载 - 热部署 / 模块化(OSGi、JPMS):每次更新用新 ClassLoader 加载,旧 ClassLoader 连同类一起卸载,避免重启——必须绕过默认委派逻辑
打破的关键是重写 loadClass(),而不是只改 findClass();后者只是委派链末端的“干活人”,不改它,委派行为照旧。

















