为什么 JDBC 驱动不需要 Class.forName() 了?为什么同一个 jar 包在两个 ClassLoader 中加载会报 ClassCastException?答案都在类加载机制里。

一、类加载的 7 个阶段

  • 1.1 加载 → 验证 → 准备 → 解析 → 初始化 → 使用 → 卸载
  • 1.2 哪些阶段是交叉进行的
  • 1.3 类加载的触发时机——主动引用 vs 被动引用

二、类加载器层次结构

  • 2.1 Bootstrap ClassLoader——加载 <JAVA_HOME>/lib
  • 2.2 Extension ClassLoader(JDK 8)→ Platform ClassLoader(JDK 9+)
  • 2.3 Application ClassLoader——加载 classpath
  • 2.4 自定义 ClassLoader——什么时候需要

三、双亲委派模型

  • 3.1 委派流程:子 → 父 → Bootstrap(向上委派,向下查找)
  • 3.2 loadClass() 源码分析
  • 3.3 为什么这样设计——避免重复加载 + 核心类安全

四、破坏双亲委派的经典案例

  • 4.1 JDBC 驱动的加载——SPI 机制
  • 4.2 Tomcat 的 WebappClassLoader——应用隔离
  • 4.3 热部署/热替换的实现原理

五、SPI 机制深入

  • 5.1 ServiceLoader.load() 源码走读
  • 5.2 META-INF/services/ 文件的约定
  • 5.3 SPI 的缺陷——无法按需加载
  • 5.4 SPI vs API 的区别

六、线程上下文类加载器

  • 6.1 Thread.currentThread().getContextClassLoader()
  • 6.2 为什么需要它——打破双亲委派的”后门”
  • 6.3 使用场景与注意事项

七、类卸载

  • 7.1 类的卸载条件(GC Root 不可达)
  • 7.2 自定义 ClassLoader 的卸载
  • 7.3 方法区/元空间的类信息回收

八、实际案例分析

  • 8.1 ClassCastException:同一个类在不同 ClassLoader 中的”不同身份”
  • 8.2 NoClassDefFoundError vs ClassNotFoundException
  • 8.3 排查工具:-verbose:class 查看加载过程

九、总结

  • 双亲委派的本质是”安全 + 复用”
  • SPI 是”必需的破例”