双亲委派机制详解

双亲委派机制详解

双亲委派机制(Parent Delegation Model)是Java类加载器的核心设计模式,用于保证Java程序运行的安全性和稳定性。

1. 类加载器层次结构

四种类加载器

  • Bootstrap ClassLoader(启动类加载器)

    • C++实现,是JVM的一部分
    • 加载<JAVA_HOME>/lib目录下的核心类库
    • rt.jarresources.jar
  • Extension ClassLoader(扩展类加载器)

    • Java实现,父类加载器为Bootstrap ClassLoader
    • 加载<JAVA_HOME>/lib/ext目录下的扩展类库
  • Application ClassLoader(应用程序类加载器)

    • Java实现,父类加载器为Extension ClassLoader
    • 加载ClassPath路径下的类库
    • 是程序默认的类加载器
  • Custom ClassLoader(自定义类加载器)

    • 继承ClassLoader类实现的自定义加载器
    • 父类加载器为Application ClassLoader

2. 双亲委派机制工作原理

工作流程

  1. 当一个类加载器收到类加载请求时,不会立即加载
  2. 先委托给父类加载器尝试加载
  3. 父类加载器无法加载时,才由自己加载
// ClassLoader.loadClass()方法的核心逻辑
protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // 检查类是否已被加载
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            try {
                if (parent != null) {
                    // 委派给父类加载器
                    c = parent.loadClass(name, false);
                } else {
                    // 委派给Bootstrap ClassLoader
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // 父类加载器无法加载
            }
            
            if (c == null) {
                // 自己加载类
                c = findClass(name);
            }
        }
        return c;
    }
}

类加载流程示例

当应用程序加载java.lang.String类时:

  1. Application ClassLoader收到加载请求
  2. 委派给Extension ClassLoader
  3. Extension ClassLoader继续委派给Bootstrap ClassLoader
  4. Bootstrap ClassLoader在核心类库中找到并加载String
  5. 返回加载结果,避免了重复加载

3. 双亲委派机制的优势

安全性保障

  • 防止核心类库被篡改
  • 避免用户自定义的java.lang.Object类被加载
  • 保证Java程序的稳定运行
// 即使用户自定义了java.lang.String类
// 也会被Bootstrap ClassLoader加载的String类替代
public class String {
    // 这个类不会被加载执行
    public static void main(String[] args) {
        System.out.println("Custom String class");
    }
}

避免重复加载

  • 相同类只会被加载一次
  • 节省内存空间
  • 提高加载效率

命名空间隔离

  • 不同类加载器加载的类相互隔离
  • 支持应用服务器部署多个应用

4. 双亲委派机制的破坏

破坏场景

  1. JNDI服务

    • 需要Bootstrap ClassLoader加载的类调用用户代码
    • 使用线程上下文类加载器(Thread Context ClassLoader)解决
  2. OSGi框架

    • 需要灵活的类加载策略
    • 实现模块化和热部署
  3. 热部署和热替换

    • 开发工具需要重新加载修改的类
    • 应用服务器需要更新应用

线程上下文类加载器

// 获取当前线程的上下文类加载器
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

// 设置线程上下文类加载器
Thread.currentThread().setContextClassLoader(customClassLoader);

5. 自定义类加载器

实现方式

public class CustomClassLoader extends ClassLoader {
    
    private String classPath;
    
    public CustomClassLoader(String classPath) {
        this.classPath = classPath;
    }
    
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classData = loadClassData(name);
        if (classData == null) {
            throw new ClassNotFoundException();
        } else {
            return defineClass(name, classData, 0, classData.length);
        }
    }
    
    private byte[] loadClassData(String className) {
        // 实现类文件的读取逻辑
        String fileName = classPath + File.separatorChar + 
                         className.replace('.', File.separatorChar) + ".class";
        try {
            FileInputStream fis = new FileInputStream(fileName);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int b;
            while ((b = fis.read()) != -1) {
                baos.write(b);
            }
            return baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

6. 实际应用场景

应用服务器

  • Tomcat、WebLogic等应用服务器使用自定义类加载器
  • 实现应用间的类隔离
  • 支持热部署功能

插件化架构

  • Eclipse等IDE的插件系统
  • OSGi框架的模块化设计

动态加载

  • 数据库驱动加载
  • Web应用的Servlet加载
posted @ 2025-08-27 21:32  一刹流云散  阅读(52)  评论(0)    收藏  举报