题目
请解释JVM类加载机制中的双亲委派模型,并说明如何打破这种机制
信息
- 类型:问答
- 难度:⭐⭐
考点
类加载机制,双亲委派模型,自定义类加载器
快速回答
双亲委派模型是JVM类加载的核心机制:
- 类加载请求优先委派给父加载器处理
- 父加载器无法完成时才由子加载器自行加载
- 保证核心类库安全性和避免重复加载
打破双亲委派的方式:
- 重写
loadClass()方法 - 使用线程上下文类加载器
- OSGi等模块化框架的实现
解析
一、双亲委派模型原理
JVM类加载采用层级结构,包含三类加载器:
- Bootstrap ClassLoader:加载
JAVA_HOME/lib核心库(C++实现) - Extension ClassLoader:加载
JAVA_HOME/lib/ext扩展库 - Application ClassLoader:加载
CLASSPATH应用类
工作流程:
1. 子加载器收到加载请求
2. 递归委派给父加载器
3. 父加载器无法完成时抛出ClassNotFoundException
4. 子加载器调用findClass()自行加载二、代码示例:自定义类加载器
public class CustomClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 自定义加载逻辑(如从网络/加密文件加载)
byte[] classData = loadClassData(name);
return defineClass(name, classData, 0, classData.length);
}
// 打破双亲委派(不推荐常规使用)
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.startsWith("com.break.")) {
return findClass(name); // 绕过委派
}
return super.loadClass(name); // 默认委派
}
}三、打破双亲委派的场景
| 场景 | 实现方式 | 典型案例 |
|---|---|---|
| 基础类调用用户代码 | 线程上下文加载器 | JDBC DriverManager |
| 模块热部署 | 自定义loadClass逻辑 | Tomcat WebAppClassLoader |
| 代码隔离 | 类加载器命名空间 | OSGi容器 |
四、最佳实践与注意事项
- 安全建议:重写
findClass()而非loadClass()保持委派优势 - 内存泄漏风险:卸载类需同时满足
- 类实例全部GC
- Class对象无引用
- 加载器实例无引用
- 常见错误:
ClassCastException:不同加载器加载的相同类被视为不同类LinkageError:重复加载核心类(如手动加载java.lang.Object)
五、扩展知识:模块化加载
Java 9引入模块化系统后:
- 新增
PlatformClassLoader替代Extension ClassLoader - 模块依赖关系影响类加载可见性
- 通过
ModuleLayer实现更灵活的加载策略