双亲委派模型是java类加载的向上委托机制:appclassloader先委托extclassloader,再委托bootstrapclassloader,仅当父类加载器无法加载时才由子加载器自行调用findclass()加载;其核心在loadclass()的三步逻辑(查缓存→委派父类→自救加载),旨在保障类唯一性与安全性。

Java 类加载通过双亲委派模型(Parent Delegation Model)确保类的唯一性和安全性:当一个类加载器收到类加载请求时,它**不立即尝试自己加载**,而是先委托给父类加载器;只有当父类加载器无法加载(即在它的路径下找不到该类)时,子加载器才尝试自己加载。
双亲委派的核心流程
以 AppClassLoader 加载某个自定义类(如 com.example.MyService)为例:
- 应用线程调用
Class.forName("com.example.MyService")或首次主动使用该类时,触发加载 - JVM 调用当前线程上下文类加载器(通常是
AppClassLoader)的loadClass()方法 -
AppClassLoader先检查自己是否已加载过该类(避免重复加载),有则直接返回 - 没有则调用
getParent().loadClass(...),即委托给ExtClassLoader -
ExtClassLoader同样先查缓存,再委托给BootstrapClassLoader -
BootstrapClassLoader尝试从rt.jar等核心路径加载(如java.lang.String);若不是核心类,它返回null - 控制权逐级回退,最终由
AppClassLoader在classpath或jar中定位com/example/MyService.class字节码文件,读取二进制流,调用defineClass()解析为Class对象
字节码文件是如何被定位和读取的
每个类加载器负责自己管辖路径下的字节码查找:
-
BootstrapClassLoader:由 C++ 实现,不继承
ClassLoader,从$JAVA_HOME/jre/lib(如rt.jar)中加载核心类 -
ExtClassLoader:Java 实现,从
$JAVA_HOME/jre/lib/ext或java.ext.dirs指定路径加载扩展类 -
AppClassLoader:从
classpath、-cp参数或MANIFEST.MF中声明的路径加载应用类
实际读取时,类加载器调用 findClass(String name)(模板方法),将类全限定名(如 com.example.MyService)转换为路径 com/example/MyService.class,再通过 getResourceAsStream() 获取字节流,最后交由 defineClass() 完成验证、解析与连接。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
为什么需要双亲委派
主要解决两个关键问题:
-
类的唯一性:防止用户自定义一个
java.lang.Object替换系统类,保证核心 API 行为一致 - 安全性:避免恶意代码通过自定义类加载器注入同名系统类,破坏沙箱机制
例如,即使你在项目里放了一个 java/lang/String.class,AppClassLoader 也会委托给 BootstrapClassLoader 加载真正的 String,你的版本根本不会被使用。
如何打破双亲委派(特殊场景)
某些框架需要子加载器优先加载(如 Tomcat 隔离 Web 应用间的类、OSGi 动态模块):
- 重写
loadClass(String name, boolean resolve),去掉父委派逻辑,改为先调用findClass() - 或重写
findClass(),自定义字节码来源(如从网络、数据库、加密文件加载) - 注意:打破后需自行保障类型安全与类隔离,否则容易引发
LinkageError或ClassNotFoundException
典型例子是 JDBC 的 DriverManager:JDK 6+ 使用 ServiceLoader + 线程上下文类加载器,让应用类加载器能加载第三方驱动类,绕过 Bootstrap 的限制。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










