classLoader 分析

0 ClassLoader 基本介绍

参考 本人之前写的一篇虚拟机类加载机制

1 类加载器原理

不同ClassLoader 加载类的范围。

public class Test {

    public static void main(String[] args) throws Exception {

        System.out.println("---------------BootstrapClassLoader--------------------");

        URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
        Arrays.stream(urls).map(URL::toExternalForm).forEach(System.out::println);

        System.out.println("---------------ExtClassLoader--------------------");

        System.out.println(System.getProperty("java.ext.dirs"));


        System.out.println("---------------AppClassLoader--------------------");

        System.out.println(System.getProperty("java.class.path"));
    }

Java类加载器采用双亲委派模型 ,下面我们从代码上看下究竟什么是双亲双亲委派模型?1.当前ClassLoader首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。 2.当前classLoader的缓存中没有找到被加载的类的时候,委托父类加载器去加载,父类加载器采用同样的策略,首先查看自己的缓存,然后委托父类的父类去加载,一直到bootstrp ClassLoader.
3.当所有的父类加载器都没有加载的时候,再由当前的类加载器加载,并将其放入它自己的缓存中,以便下次有加载请求的时候直接返回。

  • 为什么要使用双亲委派模型?
    1.安全考虑, 避免自定义类覆盖了jdk 核心类,强制加载会报java.lang.SecurityException: Prohibited package name: java.lang2.避免重复加载,比如要使用JDK类就不用每个类加载器都自己加载一遍。
    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            //首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。 
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                   // 如果有父类加载器,先委派给父类加载器去加载
                    if (parent != null) 
                        c = parent.loadClass(name, false);
                    } else {
                        如果没有尝试让BootstrapClassloader 类加载器去加载
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
                // 如果都没有那自能当前classLoader 去加载
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
  • 为什么要破坏双亲委派模型?
    简单说就是隔离,防止jar 包冲突。
    在这里插入图片描述

自定义classLoader

public class MyClassLoader extends ClassLoader {
    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return super.loadClass(name);
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {

        Class<?> clazz = this.findLoadedClass(name);
        if (clazz == null) {
            byte[] classData = loadFile(name);
            if (classData == null) {
                throw new ClassNotFoundException();
            }
            clazz = defineClass(name, classData, 0, classData.length);
        }
        return clazz;
    }

    private byte[] loadFile(String name) throws ClassNotFoundException {

        String resource = name.replace('.', '/').concat(".class");
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        InputStream inputStream = null;
        try {
            inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream(resource);
            byte[] buffer = new byte[1024];
            int n;
            while (-1 != (n = inputStream.read(buffer))) {
                output.write(buffer, 0, n);
            }
            return output.toByteArray();
        } catch (Exception ex) {
            throw new ClassNotFoundException("cannot read " + name, ex);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                }
            }
        }
    }
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值