美文网首页
类加载 - 被谁加载

类加载 - 被谁加载

作者: 武曌思 | 来源:发表于2019-08-03 14:17 被阅读0次

    类加载包含两部分:一部分是被谁加载,另一部分是如何加载。
    被谁加载是指 ClassLoader 的双亲委派模型,如何加载是指类的加载过程。
    这篇博客介绍双亲委派模型,特别感谢 @书呆子Rico老师 的博客


    ClassLoader 结构核心思想

    class ClassLoader {
        /**
         * 父加载器
         */
        ClassLoader parent;
        /**
         * 已经加载的 class
         * 这个属性是我假想的,为了配合 {@link #findLoadedClass} 的猜想
         */
        Map<String, Class> loadedClasses;
    
        /**
         * 尝试从已经加载的类中寻找,如果没有返回 null
         * 真实的实现是 native 方法,我猜想是存了一个类名到类实例的映射,如下
         */
        Class<?> findLoadedClass(String name){
            return loadedClasses.get(name);
        }
    
        /**
         * 当前类加载器尝试去加载一个类,内部实现就是类的加载过程
         * 为什么说尝试?因为当前类加载器可能无法加载这个类,会返回 null
         */
        Class<?> findClass(String name){}
    
        /**
         * 双亲委派模型的实现,也是类加载的直接入口
         */
        Class<?> loadClass(String name){}
    }
    

    双亲委派模型

    当类加载器尝试加载一个类时,会首先查看自己加载过的类。如果没有查找到,不是马上去加载,而是去询问父加载器(这是一个递归的过程)。如果父加载器也没有加载,自己才会加载。双亲委派模型是通过组合的方式实现的,不是继承

    双亲委派模型图

    双亲委派实现自己实现的伪代码

    Class<?> loadClass(String name) {
        // 查找自己加载过的类
        Class<?> loadedClass = findLoadedClass(name);
        if (loadedClass == null) {
            // 尝试让父类加载
            if (parent == null) {
                // 调用 BootstrapClassLoader 去加载,后面介绍 Java 类加载器的层级结构
            } else {
                loadedClass = parent.loadClass(name);
            }
            // 如果父类没有加载,自己加载
            if (loadedClass == null) {
                loadedClass = findClass(name);
            }
        }
        // 返回最终结果,此时还有可能为 null
        // 如果当前类加载器有子加载器,则子加载器还会尝试加载,否则就会包 ClassNotFoundException
        return loadedClass;
    }
    

    双亲委派作用

    • 防止类重复加载提高效率
    • 保证核心类安全,无法被替换
      假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的类,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。

    Java 类加载器层级结构

    如双亲委派模型图中展示的,Java 中现有类加载器分三层。

    • BootstrapClassLoader,启动类加载器,顶级类加载器,由 native 实现,加载JAVA_HOME/lib下面的核心类库或-Xbootclasspath选项指定的jar包等虚拟机识别的类
    • ExtClassLoader,拓展类加载器,父加载器是BootstrapClassLoader,所以parent==null,加载JAVA_HOME /lib/ext或者由系统变量-Djava.ext.dir指定位置中的类
    • AppClassLoader,系统类加载器,默认的类加载器,也是自定义类加载器的父加载器,加载当前类所在路径及其引用的第三方类。

    相关文章

      网友评论

          本文标题:类加载 - 被谁加载

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