打破双亲委派本质是重写loadClass方法以改变委托顺序:Tomcat通过WebAppClassLoader优先自行加载应用类实现隔离,JDBC借助线程上下文类加载器实现父加载器调用子加载器加载驱动。

Java 类加载器打破双亲委派机制,本质不是“错误”,而是对标准模型的有意识绕过——关键在重写 loadClass 方法,改变默认的“先向上委托、再向下加载”流程。
为什么必须打破双亲委派?
双亲委派保障了核心类(如 java.lang.Object)不被篡改,但也带来两个硬性限制:
-
无法向下委托:父加载器不能调用子加载器加载类,导致 JDBC 中
DriverManager(Bootstrap 加载)找不到应用级驱动类(AppClassLoader 加载); - 类路径强耦合:多个 Web 应用共用同一个 Application ClassLoader,Spring 5 和 Spring 6 的同名类会冲突,无法隔离。
Tomcat 如何打破实现应用隔离?
Tomcat 为每个 Web 应用创建独立的 WebAppClassLoader,它继承自 URLClassLoader,但重写了 loadClass:
- 对
javax.servlet.*等 API 包,仍走双亲委派(委托给共享的CommonClassLoader); - 对应用自身的
com.example.*类,**优先自己加载**,避免被上级加载器提前加载; - 加载失败后才委托父加载器,彻底反转委派顺序。
JDBC 驱动加载为何必须破坏委派?
DriverManager 由 Bootstrap ClassLoader 加载,但它要加载用户提供的 com.mysql.cj.jdbc.Driver(位于 classpath,只能由 AppClassLoader 加载)。JDK 借助线程上下文类加载器(Thread.currentThread().getContextClassLoader())绕过双亲链:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
-
ServiceLoader.load(Driver.class)内部使用上下文类加载器查找META-INF/services/java.sql.Driver; - 该类加载器通常是 AppClassLoader,能访问应用 jar 包中的驱动实现;
- 这就实现了“父加载器通过子加载器完成加载”,属于典型的反向委派。
自定义类加载器打破委派的通用写法
真正打破的关键是重写 loadClass,而非只重写 findClass(后者只是加载逻辑,不改变委派行为):
- 先调用
findLoadedClass检查是否已加载; - **跳过父加载器调用**,直接执行
findClass尝试本地加载; - 仅当本地加载失败时,才调用
super.loadClass回退到标准委派。
这种写法让类加载决策权回归自身,适用于热部署、插件化、模块隔离等场景。

















