打破双亲委派模型需重写loadClass方法以调整委托顺序,而非仅重写findClass;典型应用包括Tomcat的WebappClassLoader(本地优先)、JDBC通过TCCL实现父调子、以及自定义ClassLoader切断parent引用等。

Java 中打破双亲委派模型,不是为了绕过安全机制,而是为了解决实际工程问题——比如 Web 应用隔离、JDBC 驱动加载、热部署等。核心在于**改变 loadClass 方法的执行逻辑**,让类加载器不再“先向上委托、再向下加载”,而是按需调整顺序。
重写 loadClass 实现本地优先加载
这是最直接、最常用的打破方式,Tomcat 的 WebappClassLoader 就是典型代表:
- 不调用 super.loadClass() 启动委派链,而是先调用 findClass() 尝试从 WEB-INF/classes 或 WEB-INF/lib 中加载
- 仅对 java.*、javax.*、sun.* 等系统包或显式配置的类名,才调用父加载器(如 SharedClassLoader)
- 加载失败后,再 fallback 到 super.loadClass(),形成“先自己、再父类”的反向流程
使用线程上下文类加载器(TCCL)
JDBC 是该模式的经典案例:DriverManager 由 Bootstrap 加载,但 mysql-connector-java.jar 中的 Driver 类只能由应用类加载器加载。JDK 借助 TCCL 实现“父调子”:
- 应用启动时,通过 Thread.currentThread().setContextClassLoader() 设置当前线程的类加载器为 AppClassLoader
- ServiceLoader.load(Driver.class) 内部会读取 TCCL,从而成功加载应用级驱动类
- 这本质上是绕过双亲委派链,在运行时动态指定加载主体
自定义父子关系或破坏 parent 引用
某些场景下,开发者会显式切断默认的 parent 关系,避免无意委派:
立即学习“Java免费学习笔记(深入)”;
- 构造自定义 ClassLoader 时传入 null 作为 parent,使其无法向上委托(慎用,需自行处理 java.* 类)
- 或在 loadClass 中忽略 parent 字段,完全自主控制字节码来源(如从网络、数据库、加密文件加载)
- Spring Boot 的 RestartClassLoader、OSGi 的 BundleClassLoader 都采用类似思路实现模块边界
注意:findClass 重写 ≠ 打破双亲委派
很多初学者误以为只要重写了 findClass 就算打破委派,其实不然:
- findClass 只负责“怎么加载”,不决定“谁来加载”
- 真正的委派行为由 loadClass 控制;若 loadClass 未被重写,仍会先走 parent.loadClass()
- 必须重写 loadClass,并在其中调整调用顺序,才算真正打破


















