题目
如何理解JVM的双亲委派模型?请描述其工作原理并举例说明如何打破该机制
信息
- 类型:问答
- 难度:⭐⭐
考点
类加载机制,双亲委派模型,自定义类加载器
快速回答
双亲委派模型是JVM类加载的核心机制:
- 类加载请求优先委派给父加载器处理
- 避免重复加载,保证核心类库安全
- 破坏方式:重写
loadClass()方法或使用线程上下文加载器
一、双亲委派模型原理
JVM类加载采用分层委托机制:
- 当加载类时,子加载器首先委托父加载器尝试加载
- 父加载器无法完成时,子加载器才自己加载
- 加载器层级:Bootstrap → Extension → Application → Custom
// 类加载器委派逻辑伪代码
protected Class<?> loadClass(String name, boolean resolve) {
synchronized (getClassLoadingLock(name)) {
// 1. 检查是否已加载
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
// 2. 委托父加载器
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {}
// 3. 父加载器失败后自行加载
if (c == null) {
c = findClass(name);
}
}
return c;
}
}二、打破双亲委派的场景
方式1:重写loadClass()方法
public class CustomClassLoader extends ClassLoader {
@Override
protected Class<?> loadClass(String name, boolean resolve) {
// 自定义加载逻辑(跳过委派)
if (name.startsWith("com.break.")) {
return findClass(name);
}
return super.loadClass(name, resolve);
}
}方式2:线程上下文加载器(SPI机制)
// JDBC驱动加载示例
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
// 底层使用Thread.currentThread().getContextClassLoader()三、最佳实践与注意事项
- 安全建议:非必要不破坏双亲委派,避免核心类被篡改
- 应用场景:
- 热部署(如Tomcat为每个Web应用单独加载类)
- 加载不同版本依赖(OSGi模块化)
- SPI服务发现(JDBC/JNDI)
- 常见错误:
- 破坏后未正确处理类依赖导致
LinkageError - 自定义加载器未正确设置父加载器
- 内存泄漏:未及时清理加载的类
- 破坏后未正确处理类依赖导致
四、扩展知识
- 模块化系统:Java 9的Module Layer提供新的隔离机制
- 类卸载条件:加载器实例被回收 + 所有类实例被回收
- 沙箱安全:委派机制防止恶意代码冒充核心类(如
java.lang.String)