Java的双亲委派机制(Parent Delegation Model)是JVM类加载过程中的核心原则,它通过层级化的类加载器结构确保类加载的安全性、唯一性和稳定性。以下是其核心要点:
📚 一、核心定义
-
工作原则
当一个类加载器收到加载请求时,不会立即自行加载,而是先将请求委派给父类加载器处理。每一层加载器均遵循此规则,直至顶层的启动类加载器。若父加载器无法完成加载(如类不存在),子加载器才会尝试加载。- 层级结构:
- 启动类加载器(Bootstrap ClassLoader):C++实现,加载
JAVA_HOME/lib的核心库(如rt.jar),无法被Java代码直接引用。 - 扩展类加载器(Extension ClassLoader):加载
JAVA_HOME/lib/ext目录的扩展类库,父加载器为启动类加载器。 - 应用类加载器(Application ClassLoader):加载用户类路径(ClassPath)的类,默认的系统类加载器。
-
类唯一性
一个类的唯一性由类全限定名 + 加载它的类加载器实例ID共同决定。即使同一Class文件被不同加载器加载,JVM也会视为两个不同的类。
⚙️ 二、工作流程
以ClassLoader.loadClass()方法为例:
- 检查已加载:调用
findLoadedClass()检查类是否已加载,是则直接返回。 - 委派父加载器:若未加载,递归调用父加载器的
loadClass()(若父加载器为null则委托给启动类加载器)。 - 自行加载:若所有父加载器均加载失败(抛出
ClassNotFoundException),当前加载器调用findClass()从本地路径加载。
// 简化代码逻辑
public Class<?> loadClass(String name) {
Class<?> c = findLoadedClass(name); // 步骤1
if (c == null) {
if (parent != null) {
c = parent.loadClass(name); // 步骤2
} else {
c = findBootstrapClassOrNull(name);
}
if (c == null) {
c = findClass(name); // 步骤3
}
}
return c;
}
🛡️ 三、核心作用
- 安全性
防止恶意代码替换核心类(如java.lang.String),确保JVM基础行为不受篡改。 - 避免重复加载
父加载器已加载的类,子加载器不会重复加载,节省内存并保证类全局唯一。 - 隔离性
不同加载器的命名空间隔离,避免类冲突(如Web容器中多应用隔离)。
⚖️ 四、打破双亲委派的场景
尽管是默认机制,以下场景需主动破坏:
- SPI(Service Provider Interface)
JDBC等SPI服务中,核心库(如java.sql.Driver)由启动类加载器加载,但厂商驱动(如mysql-connector.jar)需由应用类加载器加载。通过线程上下文类加载器(Thread Context ClassLoader) 反向委派实现。 - 热部署与模块化
OSGi、Tomcat等容器需动态更新类,通过自定义类加载器优先加载自身路径的类,而非委派父加载器。 - 加载非标准类
如动态生成字节码(ASM)、非Class文件资源等。
⚠️ 五、优缺点
| 优点 | 缺点 |
|---|---|
| ✅ 确保核心类库安全 | ❌ 灵活性受限(如热部署难实现) |
| ✅ 避免类重复加载 | ❌ 自定义类加载逻辑复杂 |
| ✅ 隔离不同模块的类 | ❌ 父加载器无法访问子加载器的类 |
💎 总结
双亲委派机制是JVM类加载的基石,通过自底向上委派、自顶向下加载的层级链,平衡了安全性与一致性。但在模块化、热更新等场景下,需结合线程上下文加载器或自定义加载器打破限制。理解其原理对解决类冲突、设计中间件至关重要。

被折叠的 条评论
为什么被折叠?



