likes
comments
collection
share

JVM虚拟机之双亲委派

作者站长头像
站长
· 阅读数 15

本文源自Recently祝祝,创自Recently祝祝。转载请标注出处。

此解决方式在企业中有所应用,适合Java初级开发学习,参考。

本文字数与行数,耐心阅读必有收获。

JVM虚拟机之双亲委派

1.什么是双亲委派机制?

主观理解:

当一个类加载器接收到类加载任务的时候,会先将这个类交给父类加载器加载,会先从类加载器先加载,如果没有找到,则会进入扩展类加载器加载,如果没有找到,则到应用加载器加载,最后自定义加载器,如果还是找不到该类,则会抛出ClassNotFoundException 异常。

父类无法加载,才会去子类找,然后加载该类。

JVM虚拟机之双亲委派

简要理解:

.class文件首先会从应用程序类加载器进来,毕竟我们的项目就属于一个应用程序,而类的加载首先加载应用程序类加载器的父类加载器,在它的上边有两个类加载器,一个是启动类加载器、一个是扩展类加载器,类加载的顺序是从上到下加载,加载到应用程序类加载器还找到该类的情况下,才会去加载自定义类加载器。所以一开始类的加载就委派到了双亲那里去加载,所以称之为双亲委派机制。

也就是说当应用程序启动时,Application ClassLoader会被创建并加入到虚拟机中。然后,它会根据指定的类路径来查找和加载应用程序所需的类文件。在类加载过程中,Application ClassLoader会先委托其父类加载器(Extension ClassLoaderBootstrap ClassLoader)来尝试加载类文件,如果父类加载器无法加载,那么就由Application ClassLoader自己来加载。所以类加载的时候的双亲委派也就是先在父类加载器中寻找该类。

而我们自己开发的Java类编译成.class文件之后打成Jar包之后,最终也是由应用程序类来加载这些文件的。

根据上图可以做出判断。

2.为什么要进行双亲委派机制?

安全因素的趋势下,存在双亲委派机制。双亲委派可以避免一个类被重新加载,并且保证父类的完整性。在父类存在该类的情况下,父类就进行该类的加载,不需要在进行ClassLoader再次加载一次。

3.双亲委派机制源码:

作为一个Java程序员,你应该学会看点源码。

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // 首先, 检查class是否被加载,如果没有加载则进行加载
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {//如果父类加载不为空,则交给父类加载器加载
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }
            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方法来查找该类。最后,如果需要对该类进行解析(即将符号引用转换为直接引用),则会调用resolveClass方法进行解析。如果最终还是无法加载该类,则会抛出ClassNotFoundException异常。

类的加载中呢是,自底部向上检查该类是否被加载,加载了则返回,没有加载则继续往上寻找。如果找到启动类还是没有查找到该类被加载了。则会从启动类开始寻找改类进行加载。

JVM虚拟机之双亲委派

图片做补充说明,文字有点长,但是看完整篇文章充分理解之后,那么双亲委派你就已经充分掌握了。