面试知识库
极高 进阶

双亲委派模型#

一句话答案#

类加载请求先委托父加载器(Bootstrap→Extension/JDK 9+ 为 Platform→Application),父无法加载时子才加载,防止核心类被篡改。

核心要点

加载顺序: Bootstrap(核心库) → Extension(扩展库) → Application(应用类) (JDK 9 起模块化:rt.jar 和扩展机制被移除,Extension ClassLoader 改为 Platform ClassLoader,负责 java.sql 等平台模块)

好处: 防止核心类被篡改(如自定义java.lang.String) / 避免类重复加载

打破方式: TCCL(SPI) / 重写loadClass / OSGi / Tomcat

面试回答(2分钟版)

双亲委派模型规定类加载时不会自己先尝试加载,而是把请求逐级委托给父加载器,从 Application ClassLoader 到 Extension ClassLoader 再到 Bootstrap ClassLoader,只有父加载器反馈自己无法加载时,子加载器才会尝试自己加载。这个机制的核心价值有两个:第一是安全性,防止用户自定义一个 java.lang.String 来替换核心类,因为请求一定会先到 Bootstrap ClassLoader 加载 rt.jar 中的原版;第二是避免类的重复加载,同一个类始终由同一个加载器加载(JVM 里类的身份 = 全限定名 + 加载它的类加载器,不同加载器仍可各加载一份)。JDK 9 起 Extension ClassLoader 已改为 Platform ClassLoader,rt.jar 也被模块镜像取代,但委派思路不变。但有些场景需要打破双亲委派:SPI 机制中核心接口在 Bootstrap 加载但实现类在应用层,Bootstrap 看不到应用层的类,所以通过线程上下文类加载器 TCCL 反向委托给 Application ClassLoader 加载实现类;Tomcat 为了让不同 WebApp 能加载同名类的不同版本,每个 WebApp 有独立的 WebAppClassLoader,JVM 核心类仍先交 Bootstrap 加载,其余类优先在自己的 WEB-INF 下加载、找不到再委托父加载器;还有 OSGi 实现模块化热部署也打破了委派链。

追问与易错

追问方向:

  • “为什么要有双亲委派?”→ 防止核心类被篡改,如自定义 java.lang.String
  • “怎么打破双亲委派?三种方式?”→ ① SPI 机制通过线程上下文类加载器(TCCL)反向委托 ② 重写 loadClass() 方法跳过委派逻辑 ③ OSGi/Tomcat 的 WebAppClassLoader 优先自己加载再委托父加载器
  • “Tomcat 的类加载为什么要打破双亲委派?”→ 不同 WebApp 可能依赖同名类的不同版本

易错点:

  • ❌ “双亲委派不可打破”——SPI/Tomcat/OSGi 都打破了
  • ❌ “委派”理解为”双亲都参与”——其实是单链委派到顶,不是两个父亲