侧边栏壁纸
博主头像
月伴飞鱼 博主等级

行动起来,活在当下

  • 累计撰写 39 篇文章
  • 累计创建 25 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

如何实现一个类加载器?为什么是LoadClass而不是FindClass?

月伴飞鱼
2025-03-09 / 0 评论 / 1 点赞 / 5 阅读 / 0 字
温馨提示:
部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

如何实现一个类加载器?

要实现一个类加载器,可以继承 ClassLoader 类并根据需求重写相关方法。

以下是具体实现方式:

遵循双亲委派模型

如果希望类加载器遵循双亲委派原则,只需重写 findClass 方法即可。

public class MyClassLoader extends ClassLoader {

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // 自定义加载逻辑,例如从文件中加载类的字节码
        byte[] classBytes = loadClassData(name);
        if (classBytes == null) {
            throw new ClassNotFoundException(name);
        }
        return defineClass(name, classBytes, 0, classBytes.length);
    }

    private byte[] loadClassData(String name) {
        String filePath = name.replace('.', '/').concat(".class");
        try (InputStream input = new FileInputStream(filePath);
             ByteArrayOutputStream output = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = input.read(buffer)) != -1) {
                output.write(buffer, 0, bytesRead);
            }
            return output.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

特点:findClass 方法只在父类加载器无法加载目标类时调用,因此遵循双亲委派模型。

破坏双亲委派模型

如果需要实现自己的类加载逻辑而不遵循双亲委派原则,可以重写 loadClass 方法。

public class CustomClassLoader extends ClassLoader {

    @Override
    public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            // 检查类是否已加载
            Class<?> loadedClass = findLoadedClass(name);
            if (loadedClass == null) {
                if (shouldUseParent(name)) {
                    try {
                        loadedClass = getParent().loadClass(name);
                    } catch (ClassNotFoundException ignored) {
                    }
                }
                if (loadedClass == null) {
                    loadedClass = findClass(name); // 调用自定义加载逻辑
                }
            }
            if (resolve) {
                resolveClass(loadedClass);
            }
            return loadedClass;
        }
    }

    private boolean shouldUseParent(String name) {
        // 可根据类名决定是否优先使用父类加载器
        return !name.startsWith("com.example.custom");
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classBytes = loadClassData(name);
        if (classBytes == null) {
            throw new ClassNotFoundException(name);
        }
        return defineClass(name, classBytes, 0, classBytes.length);
    }
}

特点:通过重写 loadClass 方法实现完全的类加载逻辑控制,可以选择不优先使用父类加载器,从而破坏双亲委派模型。

为什么是 loadClass 而不是 findClass

loadClass 的职责

loadClass 是类加载过程的入口方法,它控制整个类加载流程,包括:

  1. 检查类是否已加载(调用 findLoadedClass)。

  2. 优先委托给父类加载器(调用 getParent().loadClass)。

  3. 自定义加载逻辑(调用 findClass)。

findClass 的职责

findClassClassLoader 的钩子方法,仅在父类加载器无法加载类时调用,用于实现自定义加载逻辑。

它不负责双亲委派,只关注加载字节码并定义类。

重写方法的区别

  • 如果重写 findClass,依然遵循双亲委派模型,因为 loadClass 的逻辑不变。

  • 如果重写 loadClass,可以完全控制类加载流程,包括是否调用父类加载器。

总结

  1. 如何实现类加载器

    • 遵循双亲委派:重写 findClass

    • 破坏双亲委派:重写 loadClass

  2. 为什么是 loadClass 而不是 findClass

    • loadClass 是类加载的总控方法,负责协调整个加载流程,包括双亲委派。

    • findClass 仅实现具体的类加载逻辑,是 loadClass 流程的一部分。

  3. 选择依据

    • 如果希望仅定制加载逻辑并保留双亲委派,重写 findClass

    • 如果需要完全自定义类加载流程,重写 loadClass

公众号.png

1
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin
    1. 支付宝打赏

      qrcode alipay
    2. 微信打赏

      qrcode weixin
博主关闭了所有页面的评论