ClassLoader双亲委派模式作用详解

 更新时间:2022年10月28日 10:27:04   作者:梦想实现家_Z  
这篇文章主要为大家介绍了ClassLoader双亲委派模式作用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

前言

我们的面试中经常会遇到关于ClassLoader的问题,但是我们的日常开发中又没有直接编写过ClassLoader相关的代码。对于小白新手来说,可能都不知道ClassLoader是用来干嘛的,它是如何在无形当中影响我们编写的代码的?

ClassLoader的作用

见名知意,ClassLoader就是类加载器,它的作用就是将我们编写的java代码加载到JVM虚拟机中。在JVM启动的时候是不会一次性把所有的java类加载进去的,而是在需要的时候才加载指定的类文件,要不然类特别多的话,大部分类一时用不上,那就浪费内存资源了。既然ClassLoader是用来加载类文件的,那么我们平时写的java代码是如何加载的呢?

ClassLoader的种类

在JDK中,默认是有三种ClassLoader的:

Bootstrap ClassLoader

主要加载核心类库,加载${JRE_HOME}/lib下的rt.jar、resources.jar等;

Extension ClassLoader

加载扩展类库,加载${JRE_HOME}/lib/ext文件夹下的jar包和class文件;

另外还会加载-D java.ext.dirs指定的目录下的jar包和class文件;

AppClassLoader

加载当前应用classpath下的所有class文件;

如何实现双亲委派模式

Launcher类中,我们可以看到Launcher创建的时候,同时创建了ExrClassLoaderAppClassLoader对象。

sun.misc.Launcher:

    public Launcher() {
        Launcher.ExtClassLoader var1;
        try {
            var1 = Launcher.ExtClassLoader.getExtClassLoader();
        } catch (IOException var10) {
            throw new InternalError("Could not create extension class loader", var10);
        }
        try {
            this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
        } catch (IOException var9) {
            throw new InternalError("Could not create application class loader", var9);
        }
        Thread.currentThread().setContextClassLoader(this.loader);
    }

1.创建ExtClassLoader对象;

2.创建AppClassLoader对象,并把ExtClassLoader对象作为AppClassLoader的父级ClassLoader;

3.把AppClassLoader对象绑定到线程上下文中;

为什么没有提到BoostrapClassLoader?

因为BoostrapClassLoader在java层面是拿不到的,ExtClassLoader的父级ClassLoader就是BoostrapClassLoader,java层面取出来就是null;

为了了解清楚类的加载方式,我们首先需要从AppClassLoader中的loadClass()方法中入手:

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 首先, 检查这个类是否已经加载好了
            Class<?> c = findLoadedClass(name);
            // 如果没有加载过
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // 如果父级ClassLoader不为空,那么就先尝试让父级ClassLoader加载
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        // 如果父级ClassLoader为空,有可能父级ClassLoader是BootstrapClassLoader,那么先尝试在BootstrapClassLoader加载
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
                // 如果一直向上都没有加载目标class,那么最终回到当前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;
        }
    }

通过以上代码分析,我们可以大概了解到双亲委派模式了:

1.先在当前ClassLoader检查是否已经加载了目标类;

2.如果当前ClassLoader没有加载目标类,那么先向尝试让父级ClassLoader加载目标类,直至BootstrapClassLoader;

3.如果最终所有的父级ClassLoader都没有加载目标类,那么当前ClassLoader尝试自己加载目标类;

4.所有父级ClassLoader重复操作1~3步骤;

5.只要其中任意一个ClassLoader成功加载目标类,那么就直接返回;

小测试

为了验证小伙伴们是否已经明白了双亲委派模式,我们出一个小小的测试题留给大家:

我们通过自己创建一个java.lang.String的类(类名和包名和JDK中的String.class一致),这个自定义的String类能不能通过AppClassLoader成功地加载到JVM中?

以上就是ClassLoader双亲委派模式作用详解的详细内容,更多关于ClassLoader双亲委派模式的资料请关注脚本之家其它相关文章!

相关文章

  • 详解SpringMVC——接收请求参数和页面传参

    详解SpringMVC——接收请求参数和页面传参

    这篇文章主要介绍了详解SpringMVC——接收请求参数和页面传参,小编觉得挺不错的,现在分享给大家,也给大家做个参考。
    2016-12-12
  • Java CountDownLatch计数器与CyclicBarrier循环屏障

    Java CountDownLatch计数器与CyclicBarrier循环屏障

    CountDownLatch是一种同步辅助,允许一个或多个线程等待其他线程中正在执行的操作的ASET完成。它允许一组线程同时等待到达一个共同的障碍点
    2023-04-04
  • 使用Java实现解析Excel公式

    使用Java实现解析Excel公式

    在日常工作中,我们经常需要在Excel中使用公式对表中数据进行计算和分析,所以本文小编主要来和大家介绍一下如何在Java中实现解析Excel公式,感兴趣的可以了解下
    2024-02-02
  • Spring发送邮件如何内嵌图片增加附件

    Spring发送邮件如何内嵌图片增加附件

    这篇文章主要介绍了Spring发送邮件如何内嵌图片增加附件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • Java线程中的interrupt详解

    Java线程中的interrupt详解

    这篇文章主要介绍了Java线程中的interrupt详解,interrupt翻译成中文为“打断”的意思,但实际上,interrupt()方法并非将一个线程打中断的意思,本文提供了部分实现代码,需要的朋友可以参考下
    2023-09-09
  • Java实现拓扑排序算法的示例代码

    Java实现拓扑排序算法的示例代码

    在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列。本文将为大家讲讲拓扑排序算法的原理及实现,需要的可以参考一下
    2022-07-07
  • Spring MVC请求转发与请求重定向的示例详解

    Spring MVC请求转发与请求重定向的示例详解

    转发指服务器接收请求后,从一个资源跳转到另一个资源中,请求转发是一次请求,不会改变浏览器的请求地址,这篇文章主要介绍了Spring MVC请求转发与请求重定向的相关知识,需要的朋友可以参考下
    2023-09-09
  • java简单实现多线程及线程池实例详解

    java简单实现多线程及线程池实例详解

    这篇文章主要为大家详细介绍了java简单实现多线程,及java爬虫使用线程池实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03
  • mybatis如何返回某列的最大值

    mybatis如何返回某列的最大值

    这篇文章主要介绍了mybatis如何返回某列的最大值操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • java数据结构与算法数组模拟队列示例详解

    java数据结构与算法数组模拟队列示例详解

    这篇文章主要为大家介绍了java数据结构与算法数组模拟队列示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06

最新评论