美文网首页java收录jvm
JVM学习(二)续1-ClassLoader代码解读-双亲委派模

JVM学习(二)续1-ClassLoader代码解读-双亲委派模

作者: J先生有点儿屁 | 来源:发表于2018-08-02 11:55 被阅读2次

    1. ClassLoader的继承关系

    ClassLoader是什么鬼?为什么我们要如此大费周章的讲解这个?
    还记得AppClassLoader、ExtClassLoader么?他们与ClassLoader之间的关系是什么?


    ClassLoader继承关系 AppClassLoader+ExtClassLoader
    URLClassLoader
    SecureClassLoader
    ClassLoader

    2. ClassLoader重要方法loadclass()代码解读。

    直接上代码,代码上注释有说明。

    ```
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }
    
    protected Class<?> loadClass(String name, boolean resolve) //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来加载。 什么时候父类不存在呢?其实就是ExtClassLoader不存在父类的情况。
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                    // 如果父类通过缓存+加载都无法找到,并抛出ClassNotFoundException异常时,则捕获异常但不处理。
                }
    
                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;
        }
    }
    ```
    

    代码中有几个关键调用需要注意:

    Class<?> c = findLoadedClass(name)通过缓存查找判断是否存在该类。
      进一步查看该方法实现,又调用了native findLoadedClass0方法。
        ```
        protected final Class<?> findLoadedClass(String name) {
            if (!checkName(name))
                return null;
            return findLoadedClass0(name);
        }
    
        private native final Class<?> findLoadedClass0(String name);
        ```
    
    ② 当parent != null时,c = parent.loadClass(name, false);。如果父类不为空,则委派给父类的loadClass()方法执行。
    当 parent == null是,```c = findBootstrapClassOrNull(name);```父类如果为空时,则委派给BootstrapClassLoader来查找。
    

    这里就是双亲委派模型出现了。

    ③ 当在经过父类们缓存查找和加载后,仍然未找到该类,则本加载器会亲自进行查找c = findClass(name);。这个方法很关键。
        ```
        protected Class<?> findClass(String name) throws ClassNotFoundException {
                throw new ClassNotFoundException(name);
            }
        ```
    

    3. 双亲委派模型的验证

        public static void main(String[] args) {
            ClassLoader loader = TestStatic3.class.getClassLoader();
            System.out.println(loader);
            System.out.println(loader.getParent());
            System.out.println(loader.getParent().getParent());
        }
    

    输出结果:

    sun.misc.Launcher$AppClassLoader@b4aac2
    sun.misc.Launcher$ExtClassLoader@193b845
    null
    

    4. 双亲委派模型的优点

    这里补充下几个双亲委派模型的特点。

    • 系统类防止内存中出现多份同样的字节码
      因为Java类随着它的类加载器一起具备了一种带有优先级的层次关系。双亲委派模型很好的解决了各个类加载器的基础类的统一问题(越基础的类由越上层的加载器进行加载)。
    • 保证Java程序安全稳定运行
      使用双亲委派模型来组织类加载器之间的关系,有一个显而易见的好处就是Java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如,类java.lang.Object,它存放在rt.jar中,无论哪一个类加载器要加载这个了类,最终都是委派给模型最顶端的启动类加载器进行加载,因此Object类在程序的各个类加载器环境中都是同一个类。
      相反,如果没有使用双亲委派模型,由各个类加载器自行去加载的话,如果用户自己编写了一个称为java.lang.Object的类,并放在程序的ClassPath中,那系统中将会出现多个不同的Object类,Java类型体系中最基本的行为也就无法保证,应用程序也会变得一片混乱。

    相关文章

      网友评论

        本文标题:JVM学习(二)续1-ClassLoader代码解读-双亲委派模

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