双亲委派机制是什么
双亲委派机制(Parent Delegation Model)是 Java 类加载器(ClassLoader)的一种工作模式。当一个类加载器收到加载请求时,先将请求委派给父类加载器,只有父类加载器无法加载时,才由自己尝试加载。这种机制确保类的唯一性,避免重复加载和核心类被篡改。
关键事实
- 核心思想:
- “先上后下”:优先由父加载器加载,子加载器最后尝试。
- 类加载器层次:
- Bootstrap ClassLoader:加载核心库(
rt.jar
,如java.lang.*
)。 - Extension ClassLoader:加载扩展库(
jre/lib/ext
)。 - Application ClassLoader:加载应用类路径(
classpath
)。 - 自定义类加载器:用户定义。
- 实现:
ClassLoader.loadClass()
方法中体现。
实现原理
流程
- 类加载器收到加载请求(如
Class.forName("com.example.MyClass")
)。 - 检查缓存(
findLoadedClass
),已加载则返回。 - 委派给父加载器(递归向上)。
- 父加载器无法加载(
findClass
失败),自己尝试加载。 - 加载成功,返回
Class
对象。
代码(简化)
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
// 检查是否已加载
Class<?> c = findLoadedClass(name);
if (c != null) return c;
// 委派父加载器
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name); // 顶层 Bootstrap
}
} catch (ClassNotFoundException e) {
// 父加载器未找到
}
// 自己加载
if (c == null) {
c = findClass(name);
}
if (resolve) resolveClass(c);
return c;
}
示例
- 加载
java.lang.String
: - AppClassLoader -> ExtClassLoader -> BootstrapClassLoader。
- Bootstrap 加载成功,返回。
- 加载
com.example.MyClass
: - AppClassLoader -> ExtClassLoader -> BootstrapClassLoader。
- 上层未找到,AppClassLoader 从
classpath
加载。
优点
- 避免重复加载:
- 父加载器已加载,子加载器直接复用。
- 安全性:
- 核心类(如
java.lang.Object
)由 Bootstrap 加载,防止用户自定义类覆盖。 - 层次清晰:
- 职责分明,加载顺序可控。
缺点
- 灵活性受限:
- 无法动态替换核心类。
- 子加载器依赖父加载器,可能不适应特殊需求(如 OSGi)。
延伸与面试角度
- 打破双亲委派:
- 方式:重写
loadClass
或自定义findClass
。 - 场景:
- Tomcat:每个 Web 应用独立类加载器。
- SPI(如 JDBC):
Thread.currentThread().getContextClassLoader()
。
- 实际应用:
- JDK:保护
java.*
包。 - Spring:依赖 ApplicationClassLoader。
- 与热部署:
- 重启类加载器实现类更新。
- 面试点:
- 问“为什么安全”时,提核心类保护。
- 问“如何打破”时,提 Tomcat 或 SPI。
总结
双亲委派机制是 Java 类加载的默认模式,上层优先加载,确保唯一性和安全性,基于 Bootstrap、Ext、App 三级结构。缺点是灵活性有限,可通过自定义打破。面试时,可画层次图或提 SPI 示例,展示理解深度。