双亲委派模型是“先请上级处理,上级不行再自己动手”的协作规则:类加载器先查缓存,再委派父加载器(逐级至bootstrap),仅当所有上级均失败时才调用findclass自行加载;java 17起分为bootstrap、platform、app和自定义四层,核心目标是保障核心类唯一性、防篡改与依赖稳定。

双亲委派模型不是“两个父母一起管”,而是“先请上级处理,上级不行再自己动手”的协作规则。它不强制所有类加载器必须遵守,但 JVM 内置的加载器默认严格执行,核心目标是让 java.lang.Object 这类基础类稳如磐石,不让业务代码意外覆盖或干扰。
它怎么一步步工作的?
当你的代码触发 Class.forName("com.example.User") 或首次使用某个类时,当前类加载器会按固定顺序响应:
-
查缓存:先看自己是否已加载过这个类(通过
findLoadedClass),有就直接返回,避免重复定义; -
交上级:调用
parent.loadClass(),把请求传给父加载器;这个动作会逐级向上,直到 Bootstrap(启动类加载器); -
自己兜底:只有所有上级都返回
null(表示找不到),当前加载器才调用findClass(),从自己的路径(如 jar 包、本地文件)读取字节码并定义成 Class 对象。
现在的类加载器分哪几层?
Java 17 起层级更清晰,不再提“扩展类加载器”这个模糊角色:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
Bootstrap 类加载器:C++ 实现,加载
java.base等核心模块(String、Object),没有 Java 对象,getClassLoader()返回null; -
Platform 类加载器:替代旧 Extension,负责
java.sql、java.xml等平台级模块; -
App 类加载器:加载 classpath 或模块路径下的业务类,默认也是线程上下文类加载器(
Thread.currentThread().getContextClassLoader()); -
自定义类加载器:继承
ClassLoader,默认父加载器是 App,重写findClass可实现热部署、插件隔离等场景。
为什么非得搞这套流程?
它解决的是运行时最底层的信任与一致性问题:
-
防篡改:你哪怕在项目里放一个
java.lang.Integer类,也不会被 App 加载器加载——因为 Bootstrap 已经加载了真正的版本,且优先权最高; -
保唯一:同一个全限定名的类,不会被不同加载器重复加载;否则两个
MyService类即使字节码一样,也会因加载器不同而无法互相赋值,抛ClassCastException; -
稳依赖:你写的类引用
java.util.List,必然走 Bootstrap 加载,不会被某插件自带的旧版 List 搞乱行为,整个链路可预期。
什么时候可以打破它?
可以,但要有明确理由,不能为了打破而打破:
-
线程上下文类加载器(TCCL):JDBC 的
DriverManager需要用 TCCL 加载第三方驱动,因为 Bootstrap 不认识这些类; -
重写
loadClass:自定义加载器跳过委托,直接调用findClass,常见于 OSGi、Spring Boot DevTools 热替换; - 模块化系统(Jigsaw):模块间显式声明依赖,部分场景绕过传统委派,由模块系统协调加载。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










