ClassLoader双亲委派模式作用详解

目录
  • 前言
  • ClassLoader的作用
  • 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双亲委派模式的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java源码解析之ClassLoader

    一.前言 一个完整的Java应用程序,当程序在运行时,即会调用该程序的一个入口函数来调用系统的相关功能,而这些功能都被封装在不同的class文件当中,所以经常要从这个class文件中要调用另外一个class文件中的方法,如果另外一个文件不存在的,则会引发系统异常.而程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,通过Java的类加载机制(ClassLoader)来动态加载某个class文件到内存当中的,从而只有class文件被载入到了内存之后,才能被其它cl

  • JAVA 笔记 ClassLoader.getResourceAsStream() 与 Class.getResourceAsStream()的区别

    Class.getResourceAsStream() 会指定要加载的资源路径与当前类所在包的路径一致. 例如你写了一个MyTest类在包com.test.mycode 下,那么MyTest.class.getResourceAsStream("name") 会在com.test.mycode包下查找相应的资源. 如果这个name是以 '/' 开头的,那么就会从classpath的根路径下开始查找. ClassLoader.getResourceAsStream() 无论要查找的资源前

  • Java ClassLoader虚拟类实现代码热替换的示例代码

    目录 总结 ClassLoader 虚拟类方法 实现代码热替换 实现 改进思考 总结 类加载器是负责加载类的对象.类ClassLoader是一个抽象类.给定类的全限定类名,类加载器应尝试查找或生成构成该类定义的数据Class文件.典型的策略是将名称转换为文件名,然后从文件系统中读取该名称的类文件 每个Class对象都包含一个Class.getClassLoader()方法可以获取到定义它的ClassLoader 数组类的Class对象不是由类加载器创建的,而是根据Java运行时的要求自动创建的.

  • Python深度学习之简单实现猫狗图像分类

    一.前言 本文使用的是 kaggle 猫狗大战的数据集 训练集中有 25000 张图像,测试集中有 12500 张图像.作为简单示例,我们用不了那么多图像,随便抽取一小部分猫狗图像到一个文件夹里即可. 通过使用更大.更复杂的模型,可以获得更高的准确率,预训练模型是一个很好的选择,我们可以直接使用预训练模型来完成分类任务,因为预训练模型通常已经在大型的数据集上进行过训练,通常用于完成大型的图像分类任务. tf.keras.applications中有一些预定义好的经典卷积神经网络结构(Applic

  • Android源码探究之BaseDexClassLoader的使用

    目录 前言 一.dexPath(String) 二.optimizedDirectory 三.librarySearchPath 四.parent 五.总结 前言 一共有4个参数,分来来讲. 1:dexFile(String类型)2:optimizedDirectory(File类型)3:librarySearchPath(String类型)4:parent(ClassLoader类型) 一.dexPath(String) 官方的注释: * @param dexPath the list of

  • SpringBoot详细讲解通过自定义classloader加密保护class文件

    目录 背景 maven插件加密 注意事项 自定义classloader 隐藏classloader 被保护class手动加壳 总结 背景 最近针对公司框架进行关键业务代码进行加密处理,防止通过jd-gui等反编译工具能够轻松还原工程代码,相关混淆方案配置使用比较复杂且针对springboot项目问题较多,所以针对class文件加密再通过自定义的classloder进行解密加载,此方案并不是绝对安全,只是加大反编译的困难程度,防君子不防小人,整体加密保护流程图如下图所示 maven插件加密 使用自

  • ClassLoader双亲委派模式作用详解

    目录 前言 ClassLoader的作用 ClassLoader的种类 如何实现双亲委派模式 小测试 前言 我们的面试中经常会遇到关于ClassLoader的问题,但是我们的日常开发中又没有直接编写过ClassLoader相关的代码.对于小白新手来说,可能都不知道ClassLoader是用来干嘛的,它是如何在无形当中影响我们编写的代码的? ClassLoader的作用 见名知意,ClassLoader就是类加载器,它的作用就是将我们编写的java代码加载到JVM虚拟机中.在JVM启动的时候是不会

  • JavaScript中闭包的写法和作用详解

    1.什么是闭包 闭包是有权访问另一个函数作用域的变量的函数. 简单的说,Javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内.而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量.参数和声明的其他内部函数.当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包. 2.变量的作用域 要理解闭包,首先要理解变量的作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变

  • JavaScript设计模式之调停者模式实例详解

    本文实例讲述了JavaScript设计模式之调停者模式.分享给大家供大家参考,具体如下: 1.定义 调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用.从而使他们可以松散偶合.当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用.保证这些作用可以彼此独立的变化.调停者模式将多对多的相互作用转化为一对多的相互作用.调停者模式将对象的行为和协作抽象化,把对象在小尺度的行为上与其他对象的相互作用分开处理. 2.使用的原因 当对象之间的交互操作很多,且每个对象的行为操

  • JVM的类加载器和双亲委派模式你了解吗

    目录 类加载器 1.启动类加载器 2.拓展类加载器 3.应用程序类加载器 4.双亲委派模式 5.自定义类加载器 5.1.使用场景 5.2.步骤 总结 类加载器 Java虚拟机设计团队有意把类加载阶段中的“通过一个类的全限定名来获取描述该类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需的类.实现这个动作的代码被称为“类加载器”(ClassLoader). 对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性,每一个

  • Java设计模式之策略模式示例详解

    目录 定义 结构 UML类图 UML序列图 深入理解策略模式 策略和上下文的关系 策略模式在JDK中的应用 该策略接口有四个实现类 策略模式的优点 策略模式的缺点 策略模式的本质 在讲策略模式之前,我们先看一个日常生活中的小例子: 现实生活中我们到商场买东西的时候,卖场往往根据不同的客户制定不同的报价策略,比如针对新客户不打折扣,针对老客户打9折,针对VIP客户打8折... 现在我们要做一个报价管理的模块,简要点就是要针对不同的客户,提供不同的折扣报价. 如果是有你来做,你会怎么做? 我们很有可

  • Fabric.js 修改画布交互方式作用详解

    目录 本文简介 动手试试 和 hasControls .hasBorders 的区别 和 StaticCanvas 的区别 总结 本文简介 fabric.js 为我们提供了很多厉害的方法.今天要搞明白的一个东西是 canvas.interactive . 官方文档对 canvas.interactive 的解释是: Indicates that canvas is interactive. This property should not be changed. canvas.interacti

  • Java结构型设计模式中代理模式示例详解

    目录 代理模式 分类 主要角色 作用 静态代理与动态代理的区别 静态代理的基本使用 创建抽象主题 创建真实主题 创建代理主题 客户端调用 JDK动态代理的基本使用 创建抽象主题 创建真实主题 创建代理主题 客户端调用 小优化 CGLIB动态代理的基本使用 创建抽象主题 创建真实主题 创建代理主题 客户端调用 小优化 CGLIB与JDK动态代理区别 1.执行条件 2.实现机制 3.性能 代理模式 代理模式(Proxy Pattern)属于结构型模式. 它是指为其他对象提供一种代理以控制对这个对象的

  • Mysql中explain作用详解

    一.MYSQL的索引 索引(Index):帮助Mysql高效获取数据的一种数据结构.用于提高查找效率,可以比作字典.可以简单理解为排好序的快速查找的数据结构. 索引的作用:便于查询和排序(所以添加索引会影响where 语句与 order by 排序语句). 在数据之外,数据库还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用数据.这样就可以在这些数据结构上实现高级查找算法.这些数据结构就是索引. 索引本身也很大,不可能全部存储在内存中,所以索引往往以索引文件的形式存储在磁盘上. 我们

  • Angular指令之restict匹配模式的详解

    Angular指令之restict匹配模式的详解 <body data-ng-app="myapp"> <runn2></runn2> <div data-runn2></div> <div class="runn2"></div> <!-- directive: runn2 --> <script> var app=angular.module("

  • bootstrap中的 form表单属性role="form"的作用详解

    html 里面的 role 本质上是增强语义性,当现有的HTML标签不能充分表达语义性的时候,就可以借助role来说明.通常这种情况出现在一些自定义的组件上,这样可增强组件的可访问性.可用性和可交互性. role的作用是描述一个非标准的tag的实际作用.比如用div做button,那么设置div 的 role="button",辅助工具就可以认出这实际上是个button 比如, <div role="checkbox" aria-checked="c

随机推荐