Java双亲委托机制:类加载的安全保障

Java中的双亲委托机制是一种类加载器的工作模式,旨在确保Java类在虚拟机中的唯一性,防止类重复加载,并保护核心API的安全性。下面我们来详细了解这个机制。

类加载器的层次结构

Java中主要有四种类加载器:

  • Bootstrap ClassLoader(启动类加载器) :负责加载Java核心类库,如java.lang.Object
  • Extension ClassLoader(扩展类加载器) :加载扩展类库,通常位于jre/lib/ext目录下。
  • Application ClassLoader(应用类加载器) :加载应用程序的类,通常是用户编写的类。
  • User ClassLoader(用户自定义类加载器) :用户可以自定义的类加载器,用于特殊场景。

每个类加载器都有一个父类加载器,除了Bootstrap ClassLoader,它没有父类加载器。

委托加载过程

  1. 请求委托:当一个类加载器收到类加载请求时,它不会直接加载,而是将请求委托给其父类加载器。
  2. 逐级委托:父类加载器继续将请求委托给其父类加载器,直到Bootstrap ClassLoader。
  3. 尝试加载:如果Bootstrap ClassLoader无法加载该类,则会逐层向下委托给子类加载器尝试加载。
  4. 自行加载:只有当父类加载器无法加载时,子类加载器才会尝试自己加载该类。

示例代码

下面是一个简单的自定义类加载器示例,展示如何重写loadClass()方法:

java 复制代码
java
import java.lang.reflect.Method;

public class CustomClassLoader extends ClassLoader {
    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        // 首先尝试通过父类加载器加载
        try {
            return super.loadClass(name, resolve);
        } catch (ClassNotFoundException e) {
            // 如果父类加载器无法加载,则尝试自己加载
            try {
                byte[] classBytes = getClassBytes(name); // 自定义方法获取类字节码
                return defineClass(name, classBytes, 0, classBytes.length);
            } catch (Exception ex) {
                throw new ClassNotFoundException(name, ex);
            }
        }
    }

    // 自定义方法获取类字节码
    private byte[] getClassBytes(String className) {
        // 这里需要实现获取类字节码的逻辑,例如从文件系统或网络读取
        // 这里省略具体实现
        return null;
    }

    public static void main(String[] args) throws Exception {
        CustomClassLoader customClassLoader = new CustomClassLoader();
        Class<?> clazz = customClassLoader.loadClass("CustomClass");
        Method method = clazz.getMethod("customMethod");
        Object instance = clazz.newInstance();
        method.invoke(instance);
    }
}

双亲委托机制的作用

  • 防止类重复加载:通过委托父类加载器检查是否已经加载过该类,避免重复加载。
  • 保证核心API安全性:防止开发者覆盖核心类库中的类,因为这些类最终都是由Bootstrap ClassLoader加载的。

打破双亲委托机制

如果需要打破双亲委托机制,可以通过自定义类加载器并重写loadClass()方法来实现。这种方法通常用于特殊场景下需要绕过双亲委托的限制。

示例:打破双亲委托

下面是一个打破双亲委托的示例,直接在子类加载器中加载类,而不委托给父类加载器:

scala 复制代码
java
public class BreakDelegationClassLoader extends ClassLoader {
    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        // 直接尝试自己加载,而不委托给父类加载器
        try {
            byte[] classBytes = getClassBytes(name); // 自定义方法获取类字节码
            return defineClass(name, classBytes, 0, classBytes.length);
        } catch (Exception e) {
            throw new ClassNotFoundException(name, e);
        }
    }

    // 自定义方法获取类字节码
    private byte[] getClassBytes(String className) {
        // 这里需要实现获取类字节码的逻辑,例如从文件系统或网络读取
        // 这里省略具体实现
        return null;
    }
}

这种方式通常用于特殊场景,如动态加载类或需要绕过双亲委托的限制时。

相关推荐
weixin_4624462310 分钟前
使用 Go 实现 SSE 流式推送 + 打字机效果(模拟 Coze Chat)
开发语言·后端·golang
JIngJaneIL28 分钟前
基于springboot + vue古城景区管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
敲敲了个代码35 分钟前
隐式类型转换:哈基米 == 猫 ? true :false
开发语言·前端·javascript·学习·面试·web
小信啊啊1 小时前
Go语言切片slice
开发语言·后端·golang
liang_jy1 小时前
Android LaunchMode
android·面试
JustHappy1 小时前
「chrome extensions🛠️」我写了一个超级简单的浏览器插件Vue开发模板
前端·javascript·github
LYFlied1 小时前
【每日算法】LeetCode 17. 电话号码的字母组合
前端·算法·leetcode·面试·职场和发展
阿里嘎多学长2 小时前
2025-12-16 GitHub 热点项目精选
开发语言·程序员·github·代码托管
Victor3563 小时前
Netty(20)如何实现基于Netty的WebSocket服务器?
后端
缘不易3 小时前
Springboot 整合JustAuth实现gitee授权登录
spring boot·后端·gitee