Java 自定义ClassLoader

本文详细介绍了Java中的双亲委派模型,该模型在类加载过程中的作用以及如何在自定义ClassLoader时遵循或不遵循这一模型。内容涵盖了BootStrap ClassLoader、Extension ClassLoader和App ClassLoader的职责,以及如何通过自定义加载器来改变加载行为。此外,还讨论了在不同场景下使用自定义ClassLoader的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

双亲委派模型

不是继承关系,是组合关系. 子加载器拥有父加载器的实例

加载流程,如下:
1. 当前类加载器首先查询该类是否已加载, 若没加载,则跳(2)
2. 委托父加载器加载,父加载器执行相同的操作,如加载失败,则跳(3)
3. 使用启动类加载器加载, 若报错,则跳(4)
4. 使用自身去加载,若报错,则加载失败

[1,2,3]的实现在ClassLoader#loadClass方法中

[4]的实现在ClassLoader#findClass方法中

系统类加载器

BootStrap ClassLoader

加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类

Extension ClassLoader

加载$JAVA_HOME中jre/lib/ext/*.jar或-Djava.ext.dirs指定目录下的jar包

App ClassLoader

加载CLASSPATH或-Djava.class.path所指定的目录下的类和jar包

自定义加载器

遵循 双亲委派模型

只需重写ClassLoader#findClass

public class MyClassLoader extends ClassLoader {

    private String path = null;

    public MyClassLoader(String path) {
        this.path = path;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte[] bytes = loadByte(name);
            return defineClass(name, bytes, 0, bytes.length);
        } catch (Exception e) {
            throw new ClassNotFoundException("类找不到" + name);
        }
    }

    private byte[] loadByte(String name) throws Exception {
        String fileName = path + File.separator + replaceSeparator(name) + ".class";

        try (FileInputStream fis = new FileInputStream(fileName)) {
            byte[] data = new byte[fis.available()];
            fis.read(data);
            return data;
        } catch (Exception e) {
            throw e;
        }
    }

    private String replaceSeparator(String name) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < name.length(); i++) {
            if (name.charAt(i) != '.') {
                sb.append(name.charAt(i));
            } else {
                sb.append(File.separator);
            }
        }
        return sb.toString();
    }

    public static void main(String[] args) throws Exception {
        MyClassLoader classLoader = new MyClassLoader("/home/wyj");
        Runtime.getRuntime().exec("javac /home/wyj/Test.java");
        Class<?> test = classLoader.loadClass("Test");
        System.out.println(test.getClassLoader());
    }
}

不遵循 双亲委派模型

public class MyClassLoader extends ClassLoader {

    private String path = null;

    public MyClassLoader(String path) {
        this.path = path;
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        Class clazz = null;

        clazz = findLoadedClass(name);
        if (clazz == null) {
            try {
                clazz = findClass(name);
            } catch (Exception e) {
            }
        }

        if (clazz == null) {
            clazz = super.loadClass(name);
        }
        return clazz;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte[] bytes = loadByte(name);
            return defineClass(name, bytes, 0, bytes.length);
        } catch (Exception e) {
            throw new ClassNotFoundException("类找不到" + name);
        }
    }

    private byte[] loadByte(String name) throws Exception {
        String fileName = path + File.separator + replaceSeparator(name) + ".class";

        try (FileInputStream fis = new FileInputStream(fileName)) {
            byte[] data = new byte[fis.available()];
            fis.read(data);
            return data;
        } catch (Exception e) {
            throw e;
        }
    }

    private String replaceSeparator(String name) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < name.length(); i++) {
            if (name.charAt(i) != '.') {
                sb.append(name.charAt(i));
            } else {
                sb.append(File.separator);
            }
        }
        return sb.toString();
    }

    public static void main(String[] args) throws Exception {
        MyClassLoader classLoader = new MyClassLoader("/home/wyj");
        Runtime.getRuntime().exec("javac /home/wyj/Test.java");
        Class<?> test = classLoader.loadClass("Test");
        System.out.println(test.getClassLoader());
    }
}

Test.java

public class Test {
}

使用场景

遵循

不遵循

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值