1. 双亲委派模型介绍

JVM对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。

而且加载某个类的class文件时,每个类都有一个对应它的类加载器,系统中的ClassLoader在协同工作的时候会默认使用双亲委派模型。

即,当某个类加载器需要加载某个.class字节码文件时,它首先把这个任务委托给它的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。

它是一种任务委派模式。


2. 双亲委派模型的工作原理?

【1】如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去执行;

【2】如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器;(每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载器中。)

【3】如果父类加载器可以完成类加载任务,就成功返回;倘若父类加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载。

以上便是双亲委派模型的工作原理。

双亲委派模型对于保证Java程序的稳定运作极为重要,但它的实现却异常简单,用以实现双亲委
派的代码只有短短十余行,全部集中在java.lang.ClassLoader的loadClass()方法之中。

举个栗子:

public class ClassLoaderDemo {public static void main(String[] args) {System.out.println("ClassLoaderDemo's ClassLoader is ========================> " + ClassLoaderDemo.class.getClassLoader());System.out.println("The Parent of ClassLoaderDemo's ClassLoader is ==========> " + ClassLoaderDemo.class.getClassLoader().getParent());System.out.println("The GrandParent of ClassLoaderDemo's ClassLoader is =====> " + ClassLoaderDemo.class.getClassLoader().getParent().getParent());}
}

测试结果:

ApplicationClassLoader的父类加载器是ExtClassLoader

ExtClassLoader的父类加载器为null,null并不代表ExtClassLoader没有父类加载器,而是 BootstrapClassLoader 。

其实这个双亲翻译的容易让别人误解,我们一般理解的双亲都是父母,这里的双亲更多地表达的是“父母这一辈”的人而已,并不是说真的有一个 Mother ClassLoader 和一个 Father ClassLoader 。另外,类加载器之间的“父子”关系也不是通过继承来体现的,是由“优先级”来决定。官方 API 文档对这部分的描述如下:

The Java platform uses a delegation model for loading classes. The basic idea is that every class loader has a "parent" class loader. When loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.


3. 双亲委派模型实现源码分析

双亲委派模型的实现代码非常简单,逻辑非常清晰,都集中在java.lang.ClassLodaer的loaderClass()中,相关代码如下所示:

protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{synchronized (getClassLoadingLock(name)) {// 首先,检查请求的类是否已经被加载过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异常// 则说明父类加载器无法完成加载请求}if (c == null) {// 在父类加载器无法加载时// 再调用本身的findClass方法来进行加载// 也就是自己尝试加载long t1 = System.nanoTime();c = findClass(name);// 这是定义类加载器;记录统计数据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】首先,在类加载时,系统先检查请求加载的类型是否已经被加载过,已经被加载的类会直接返回,倘若没有则调用父类加载器loadClass()方法,才会尝试加载;

【2】加载的时候,首先把该加载请求委派给父类加载器的loadClass()方法处理,如果父类加载器为空,则默认使用启动类加载器作为父加载器。

【3】如果父类加载器加载失败,抛出ClassNotFoundException异常,这时候才调用自己的findClass()方法尝试进行加载。

可参考网上的双亲委派模型流程图:


4. 双亲委派机制的好处?

【1】保证了Java程序的稳定运行,避免类的重复加载,保证基础类仅加载一次,不会让JVM中存在重名的类。

防止重复加载同一个.class文件,比如String.class,每次加载都委托给父加载器,最终都是BootstrapClassLoader,都保证java核心类都是BootstrapClassLoader加载的,加载过了,就不用再加载一遍,保证了java的安全与稳定性。
【2】保护程序安全,防止核心.class文件被随意篡改。

通过委托方式,不会去篡改核心.class,即使篡改也不会去加载,即使加载也不会是同一个.class对象了。不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。

如果不想使用双亲委派模型时,该如何做?

自定义加载器的话,需要继承 ClassLoader。

如果我们不想打破双亲委派模型,就重写 ClassLoader类中的 findClass()方法即可,无法被父类加载器加载的类最终会通过这个方法被加载。

但是,如果想打破双亲委派模型则需要重写 loadClass()方法


5. 如何不使用双亲委派模型?

如果我们不想打破双亲委派模型,但又不想使用双亲委派模型,就重写ClassLoader类中的findClass()方法即可,无法被父类加载器加载的类最终会通过这个方法被加载。

但是,如果想打破双亲委派模型则需要重写ClassLoader类中的loadClass()方法


6. 自定义类加载器

除了BootstrapClassLoader,其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader。如果我们要自定义自己的类加载器,很明显需要继承ClassLoader。

Java虚拟机类加载器--双亲委派模型相关推荐

  1. 由源码深入Java类加载器(双亲委派模型)

    JVM类加载器 JVM主要有以下几种类加载器: 引导类加载器 主要加载JVM运行核心类库,位于JRE的lib目录下,如rt.jar中的类. 扩展类加载器 主要加载JVM中扩展类,位于JRE的ext目录 ...

  2. java类加载和双亲委派模型浅说

    本文目录 前言 一.类加载器 1.1 类加载机制的基本特征 1.2 类加载的分类 1.3 类加载器 A.启动类加载器(引导类加载器,Bootstrap ClassLoader) B.扩展类加载器(Ex ...

  3. 类加载器-双亲委派机制

    上一篇:类加载器-分类 一.概述 除了根类加载器之外,其他的类加载器都需要有自己的父加载器.从JDK1.2开始,类的加载过程采用双亲委派机制,这种机制能够很好的保护java程序的安全.除了虚拟机自带的 ...

  4. 类加载器双亲委派模式

    双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只 ...

  5. 面向对象回顾(静态变量、类加载机制/双亲委派模型、Object类的方法、类和对象区别)

    1. 静态变量存在什么位置? 方法区 2. 类加载机制,双亲委派模型,好处是什么? 某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务, ...

  6. java虚拟机中的双亲委派机制

    文章目录 双亲委派机制 工作原理 工作场景 调用过程 三种加载器调用范围 String类加载过程 StringTest类加载过程 双亲委派机制优点 双亲委派机制 Java虚拟机对class文件采用的是 ...

  7. 类加载器-双亲委派-源码分析1

    双亲委派模式 所谓的双亲委派,就是指调用类加载器的 loadClass 方法时,查找类的规则 注意 protected Class<?> loadClass(String name, bo ...

  8. 类加载器-双亲委派-源码分析2

    public class Load5_3 {public static void main(String[] args) throws ClassNotFoundException {Class< ...

  9. JVM—类加载器和双亲委派模型

    关注微信公众号:CodingTechWork,一起工作学习总结. 文章目录 引言 类加载器 类与类加载器关系 类加载器分类 启动类加载器 扩展类加载器 应用程序类加载器 双亲委派模型 介绍 工作流程 ...

  10. java获取类加载器

    获取类加载器的方法: //扩展类加载器MainClassLoader classLoader = MainTest.class.getClassLoader();//表示当前线程的类加载器--应用程序 ...

最新文章

  1. happens-before俗解
  2. 关于对Enum的理解
  3. c#操作html dom元素,C#获取与修改HTML DOM元素信息
  4. Halcon—Tuple中符号的含义
  5. MYSQL 编码设置
  6. git常用命令之log
  7. 在实际工作中,WPS对比office,谁更强?
  8. git命令行删除远程文件
  9. 使用Eclipse Babel语言包汉化eclipse
  10. python中水量_Python居然还能用于巨大的工程项目!比如三峡发电量估算系统!
  11. Java接口配置框架magic-api
  12. 每日学习(Git和Github)
  13. 台式电脑添加共享计算机,台式电脑怎么设置wifi共享
  14. 云栖大会 | Apache Spark 3.0 和 Koalas 最新进展
  15. Python程序员必备——手把手教你配置最漂亮的PyCharm界面
  16. [模版]尽整些歪门邪道
  17. 单片机51实现计算器详细代码能自己运行
  18. 中国海洋大学2009-2010秋季学期c语言期末考试试题,中国海洋大学C语言期末笔试2010年7月A...
  19. JavaScript 数组塌陷
  20. Ubuntu18.04启用中文输入法

热门文章

  1. 中国量子技术产出居世界第二 英国量子技术未来5个发展方向
  2. vue+element的表格分页和前端搜索
  3. Jupyter Notebook 作图显示中文
  4. Linux--进程组 作业 会话 守护(精灵)进程
  5. mysql数据库管理工具navicat for mysql怎么用
  6. iOS边练边学--(Quartz2D)图片裁剪,带圆环的裁剪
  7. java开始到熟悉100-102
  8. RAC动态资源(DRM)管理介绍
  9. mysql导入hdfs参数_导入数据到HDFS
  10. vue3的语法使用总结api