侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

如何理解JVM的双亲委派模型?请描述其工作原理并举例说明如何打破该机制

2025-12-13 / 0 评论 / 4 阅读

题目

如何理解JVM的双亲委派模型?请描述其工作原理并举例说明如何打破该机制

信息

  • 类型:问答
  • 难度:⭐⭐

考点

类加载机制,双亲委派模型,自定义类加载器

快速回答

双亲委派模型是JVM类加载的核心机制:

  • 类加载请求优先委派给父加载器处理
  • 避免重复加载,保证核心类库安全
  • 破坏方式:重写loadClass()方法或使用线程上下文加载器
## 解析

一、双亲委派模型原理

JVM类加载采用分层委托机制:

  1. 当加载类时,子加载器首先委托父加载器尝试加载
  2. 父加载器无法完成时,子加载器才自己加载
  3. 加载器层级: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