美文网首页
JDK源码(二)ClassLoader之双亲委托模型

JDK源码(二)ClassLoader之双亲委托模型

作者: 李亚林1990 | 来源:发表于2019-03-15 15:08 被阅读0次

今天偶然看到一篇Java技术栈发表的文章,关于自定义类加载器的实现感觉有点问题。在此做一个梳理。
原文链接:https://www.jianshu.com/p/e808ed28a5d6
本文代码示例来自原文,稍作修改。
我们看看原文的例子:

image.png
疑问:第一时间感觉两处“return super.loadClass(name);”应该直接“return null”,不然在找不到类的情况下会死循环?!

接下来做了一番分析和验证。
自定义加载器使用中我们调用ClassLoader.loadClass加载一个类,来loadClass关于类加载双亲委托模型的实现:

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }
    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            //判断当前类是否已经被加载,调用本地方法findLoadedClass0
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    //双亲委托模型:父加载器不为空,调用父加载器加载,否则查看启动类加载器是否已加载该类
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        //调用本地方法findBootstrapClass
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
                //父加载器或者启动类加载器都未加载该类,则调用本加载器的findClass方法
                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;
        }
    }

findClass在ClassLoader中并未实现,须用户在自定义加载器中实现:

    protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }

图解双亲委托模型:


image.png

一句话总结:自底向上委托,自顶向下加载。

我们再回过头来分析找不到类的情况下代码的调用过程:
LocalClassLoader.loadClass => 父加载器返回null => LocalClassLoader.findClass失败 => super.loadClass === LocalClassLoader.loadClass
代码进入死循环

本地验证:

public class LocalClassLoader extends ClassLoader {
    private String path = "F:/study/";

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> cls = findLoadedClass(name);
        if (cls != null) {
            return cls;
        }

        if (!name.endsWith(".Key")) {
            return super.loadClass(name);
        }

        try {
            InputStream is = new FileInputStream(path + name.replace(".", "/") + ".class");
            byte[] bytes = IOUtils.readNBytes(is, is.available());
            return defineClass(name, bytes, 0, bytes.length);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return super.loadClass(name);
    }

    public static void main(String[] args) {
        try {
            LocalClassLoader lcl = new LocalClassLoader();
            Class<?> cls = lcl.loadClass("com.yalin.test.Key");   //1
            //Class<?> cls = lcl.loadClass("com.yalin.test.jdk.Key");  //2
            Field field = cls.getDeclaredField("key");
            field.setAccessible(true);
            Object value = field.get(cls.newInstance());
            System.out.println(value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

加载F:/study/目录存在的类com.yalin.test.Key,输出成功:


image.png

加载F:/study/目录不存在的类com.yalin.test.jdk.Key,代码进入死循环:


image.png

转载请备注原文链接。

相关文章

  • JDK源码(二)ClassLoader之双亲委托模型

    今天偶然看到一篇Java技术栈发表的文章,关于自定义类加载器的实现感觉有点问题。在此做一个梳理。原文链接:http...

  • 初识ClassLoader

    ClassLoader原理 ClassLoader使用双亲委托模型来对类进行搜索加载。除了最基础的BootStra...

  • Android中的classLoader

    Android中有哪几种ClassLoader?它们的作用和区别是什么? 简述ClassLoader的双亲委托模型...

  • JVM之双亲委托机制

    JVM之双亲委托机制 前言: 想了解双亲委托机制,我们就得先了解他的ClassLoader(类加载)。不管是And...

  • ClassLoader之双亲委托机制

    一、前言 无论是做Java开发,还是Android开发,ClassLoader是少不了打交道的。即便我们不围绕它做...

  • 类加载机制

    一:双亲委派机制ClassLoader#loadClass(ClassLoader源码[https://www.j...

  • 热修复原理与基础范例

    原理 ClassLoader 与 双亲委托 热修复建立的基础是 ClassLoader 的加载机制。 Androi...

  • Android的类加载器

    Android的ClassLoader与java的ClassLoader有些差异, 双亲委托机制某个类加载器在加载...

  • 安卓classloader浅析

    classloader 是采用双亲委派的方式加载所需要的类。 双亲委派:从classloader的源码分析,在加载...

  • sandBox源码分析之ClassLoader

    提起classLoader,就不由自主想起了java classLoader的双亲委派模型,那么到底什么是双亲委派...

网友评论

      本文标题:JDK源码(二)ClassLoader之双亲委托模型

      本文链接:https://www.haomeiwen.com/subject/qlilmqtx.html