什么是双亲委派机制

发布时间:2021-10-19 16:23:32 作者:iii
来源:亿速云 阅读:178
# 什么是双亲委派机制

## 目录
1. [引言](#引言)
2. [类加载器基础](#类加载器基础)
3. [双亲委派机制定义](#双亲委派机制定义)
4. [工作流程详解](#工作流程详解)
5. [实现原理分析](#实现原理分析)
6. [优势与设计意义](#优势与设计意义)
7. [打破双亲委派机制](#打破双亲委派机制)
8. [实际应用场景](#实际应用场景)
9. [常见问题与解决方案](#常见问题与解决方案)
10. [总结](#总结)

---

## 引言

在Java虚拟机(JVM)的类加载过程中,**双亲委派机制(Parent Delegation Model)** 是保证Java程序稳定运行的核心设计原则之一。该机制通过层次化的类加载器结构,有效解决了类重复加载、核心API被篡改等关键问题。本文将深入解析这一机制的实现原理、工作流程及其在Java生态中的重要意义。

---

## 类加载器基础

### 类加载器的作用
- 将.class文件加载到JVM内存
- 转换为方法区中的运行时数据结构
- 生成对应的`Class<?>`对象

### Java中的三类加载器
1. **Bootstrap ClassLoader**(启动类加载器)
   - 加载`JAVA_HOME/lib`下的核心类库(如rt.jar)
   - 唯一没有父加载器的加载器

2. **Extension ClassLoader**(扩展类加载器)
   - 加载`JAVA_HOME/lib/ext`目录的扩展类
   - 父加载器为Bootstrap

3. **Application ClassLoader**(应用程序类加载器)
   - 加载用户类路径(ClassPath)上的类
   - 父加载器为Extension

```java
// 查看类加载器示例
public class ClassLoaderDemo {
    public static void main(String[] args) {
        System.out.println(String.class.getClassLoader()); // null (Bootstrap)
        System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader()); // ExtClassLoader
        System.out.println(ClassLoaderDemo.class.getClassLoader()); // AppClassLoader
    }
}

双亲委派机制定义

核心概念

官方定义

“A class loader delegates the search for classes and resources to its parent class loader before attempting to find the class or resource itself.” —— Java官方文档


工作流程详解

标准加载流程(以加载User.class为例)

  1. AppClassLoader收到请求
  2. 立即委派给父加载器ExtClassLoader
  3. ExtClassLoader继续委派给BootstrapClassLoader
  4. Bootstrap尝试加载:
    • 成功:返回Class对象
    • 失败:通知ExtClassLoader尝试
  5. ExtClassLoader尝试加载:
    • 成功:返回Class对象
    • 失败:通知AppClassLoader尝试
  6. AppClassLoader在classpath中查找并加载
graph TD
    A[AppClassLoader] --> B[ExtClassLoader]
    B --> C[BootstrapClassLoader]
    C -->|加载失败| B
    B -->|加载失败| A

关键方法实现

ClassLoader.loadClass()的典型实现:

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 {
                    // 3. 父加载器为空则尝试Bootstrap加载
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {}
            
            if (c == null) {
                // 4. 自行查找类
                c = findClass(name);
            }
        }
        return c;
    }
}

优势与设计意义

三大核心优势

  1. 安全性保障

    • 防止核心API被篡改(如自定义java.lang.String类)
  2. 避免重复加载

    • 确保类在JVM中的唯一性(通过类加载器+全限定名标识)
  3. 职责分离

    • 每层加载器专注特定范围的类加载

典型案例分析

当用户自定义java.lang.Object类时: 1. 加载请求最终委派到BootstrapClassLoader 2. Bootstrap已加载过JRE中的Object类 3. 直接返回已加载的Class对象 4. 自定义类永远不会被加载


打破双亲委派机制

需要打破的场景

  1. SPI服务发现(如JDBC驱动加载)

    • 使用线程上下文类加载器(Thread Context ClassLoader)
  2. 热部署需求

    • OSGi框架的网状委派模型

典型实现方式

// 通过重写loadClass方法打破委派
public class CustomClassLoader extends ClassLoader {
    @Override
    protected Class<?> loadClass(String name, boolean resolve) {
        // 1. 自定义逻辑优先处理
        if (name.startsWith("com.special.")) {
            return findClass(name);
        }
        // 2. 其他类仍走双亲委派
        return super.loadClass(name, resolve);
    }
}

实际应用场景

1. Tomcat的类加载体系

graph BT
    WebApp1[WebAppClassLoader] --> Common[CommonClassLoader]
    WebApp2[WebAppClassLoader] --> Common
    Common --> Shared[SharedClassLoader]
    Shared --> Server[ServerClassLoader]
    Server --> Bootstrap

2. Spring的动态代理


常见问题与解决方案

Q1: NoClassDefFoundError vs ClassNotFoundException

异常类型 触发阶段 常见原因
ClassNotFoundException 加载阶段 类文件不存在
NoClassDefFoundError 链接阶段 类已加载但依赖缺失

Q2: 如何实现热加载?

  1. 自定义类加载器
  2. 每次修改后创建新的类加载器实例
  3. 通过反射机制调用新加载的类
// 热加载示例
public class HotSwap {
    public static void main(String[] args) throws Exception {
        while (true) {
            CustomClassLoader loader = new CustomClassLoader();
            Class<?> clazz = loader.loadClass("com.example.DynamicClass");
            Object instance = clazz.newInstance();
            clazz.getMethod("execute").invoke(instance);
            Thread.sleep(5000);
        }
    }
}

总结

双亲委派机制作为Java类加载体系的核心设计: - 通过层次化委派保证类加载的有序性 - 是Java安全模型的基石之一 - 在保持稳定性的同时允许通过特定方式扩展

随着模块化系统(JPMS)的引入,Java 9+对类加载机制进行了进一步优化,但双亲委派的基本思想仍是理解JVM类加载过程的关键所在。

最佳实践建议:在自定义类加载器时,除非有明确需求,否则应保持双亲委派机制的完整性。 “`

推荐阅读:
  1. Java类加载机制和双亲委派是什么
  2. 何为双亲委派原则

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:URLOS使用流程是怎样的

下一篇:Rust学习笔记之实现一个猜谜游戏小项目的方法教程

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》