双亲委派机制

  • 一、JVM体系结构
  • 二、双亲委派机制的含义
  • 三、双亲委派机制的源代码
  • 四、双亲委派机制的意义
  • 五、示例代码

一、JVM体系结构

我们先在这里放一张 JVM 的体系架构图,方便我们有个总体认知。

在了解JVM的双亲委派机制之前,你不得不需要知道的几个名字:本文我们只讲上图中里的类加载子系统下的三个阶段之一(Loading,加载阶段)有关的内容,即下图中用红色线圈起来的几个名词。
引导类加载器(Bootstrap ClassLoader);
扩展类加载器(Extension ClassLoader);
应用类加载器(Application ClassLoader)。

有关其详细概念请移步至:【JVM】java的jvm类加载器和类加载子系统之JVM类加载器和类加载子系统里的加载阶段,在这里就不多说了。

二、双亲委派机制的含义

当一个类加载器收到了类加载的请求的时候,它不会直接去加载指定的类,而是把这个请求委托给自己的父加载器去加载。只有父加载器无法加载这个类的时候,才会由当前这个加载器来负责类的加载。

Java中提供如下四种类型的加载器,每一种加载器都有指定的加载对象,具体如下:

  • Bootstrap ClassLoader(引导类加载器) :主要负责加载Java核心类库,%JAVA_HOME%/jre/lib/目录下,resources.jar或者sun.boot.class.path路径下的内容等。
  • Extention ClassLoader(扩展类加载器):主要负责从 java.ext.dirs 系统属性所指定的目录中加载类库,或从JDK的安装目录的**/jre/lib/ext/**子目录(扩展目录)下加载的类库。
  • Application ClassLoader(应用程序类加载器) :主要负责加载当前应用的classpath下的所有类。
  • User-Defined ClassLoader(用户自定义类加载器) : 用户自定义的类加载器,可加载指定路径的class文件。

注意:这里存在的加载器之间的层级关系并不是以继承的方式存在的,而是以组合的方式处理的。

这四种类加载器存在如下关系,当进行类加载的时候,虽然用户自定义类不会由 Bootstrap ClassLoader 或是 Extension ClassLoader 加载(由类加载器的加载范围决定),但是代码实现还是会一直委托到 Bootstrap ClassLoader, 上层无法加载,再由下层是否可以加载,如果都无法加载,就会触发 findclass(),抛出 classNotFoundException

三、双亲委派机制的源代码

打开IDEA等代码开发工具,搜索 ClassLoader 并进入类中,找到 loadClass() 方法,源代码如下:

    /*** Loads the class with the specified binary name. * This method searches for classes in the same manner as the loadClass(String, boolean) method.  * It is invoked by the Java virtual machine to resolve class references.  * Invoking this method is equivalent to invoking #loadClass(String, boolean) loadClass(name,false).** @param:  name The binary name of the class* @return:  The resulting Class object* @throws:  ClassNotFoundException If the class was not found*/public Class<?> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);}/*** Loads the class with the specified binary name.  * The default implementation of this method searches for classes in the following order:**      1. Invoke #findLoadedClass(String) to check if the class*   has already been loaded. *      2. Invoke the #loadClass(String) loadClass method*   on the parent class loader.  If the parent is null the class*   loader built-in to the virtual machine is used, instead.  *    3. Invoke the #findClass(String) method to find the*   class. * * If the class was found using the above steps, and the* resolve flag is true, this method will then invoke the #resolveClass(Class) method on the resulting Class object.** Subclasses of ClassLoader are encouraged to override * #findClass(String), rather than this method. ** Unless overridden, this method synchronizes on the result of* #getClassLoadingLock getClassLoadingLock method* during the entire class loading process.** @param: name The binary name of the class* @param: resolve If true then resolve the class* @return: The resulting Class object* @throws: ClassNotFoundException If the class could not be found*/protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// First, check if the class has already been loadedClass<?> 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 statssun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {resolveClass(c);}return c;}}

其实这段代码已经很好的解释了双亲委派机制,为了大家更容易理解,我做了一张图来描述一下上面这段代码的流程:
从上图中我们就更容易理解了,当一个 Hello.class 这样的文件要被加载时。不考虑我们自定义类加载器,首先会在 AppClassLoader 中检查是否加载过,如果有那就无需再加载了。如果没有,那么会拿到父加载器,然后调用父加载器的 loadClass() 方法。父类中同理也会先检查自己是否已经加载过,如果没有再往上。注意这个类似递归的过程,直到到达 Bootstrap ClassLoader 之前,都是在检查是否加载过,并不会选择自己去加载。直到 Bootstrap ClassLoader,已经没有父加载器了,这时候开始考虑自己是否能加载了,如果自己无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出 ClassNotFoundException。那么有人就有下面这种疑问了?

为什么为有这样的设计?下面我们再来说下这样设计的意义就明白了这样做的好处了。

四、双亲委派机制的意义

这种设计有个好处是:

  • 第一:避免类的重复加载。
  • 第二:保护程序的安全,防止核心API被随意篡改。

如果有人想替换系统级别的类,比如:String.java。篡改它的实现,在这种机制下这些系统的类已经被Bootstrap ClassLoader 加载过了(因为当一个类需要加载的时候,最先去尝试加载的就是 Bootstrap ClassLoader),所以其他类加载器并没有机会再去加载,从一定程度上防止了危险代码的植入。

  1. 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行;
  2. 如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器;
  3. 如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。
  4. 父类加载器一层一层往下分配任务,如果子类加载器能加载,则加载此类,如果将加载任务分配至系统类加载器也无法加载此类,则抛出异常。

五、示例代码

现在有一个例子,在我们自定义的 String 类中(包名是 java.lang包下创建),写一个main方法,执行它,如下:

package java.lang;public class String {static {System.out.println("这是自定义的String类!");}public static void main(String[] args) {String customClass = new String();System.out.println(customClass);}
}

执行后的结果如下:
可以看到,报错在java.lang.String中找不到类方法。因为String类是启动类加载器创建的,不是我们自定义的String类,故没有main方法。

完结!

【JVM】jvm的双亲委派机制相关推荐

  1. JVM-白话聊一聊JVM类加载和双亲委派机制源码解析

    文章目录 Java 执行代码的大致流程 类加载loadClass的步骤 类加载器和双亲委派机制 sun.misc.Launcher源码解析 Launcher实例化 Launcher 构造函数 双亲委派 ...

  2. JVM - 彻底理解打破双亲委派机制

    文章目录 Pre 双亲委派 何为打破双亲委派 如何打破双亲委派 演示 重写 ClassLoader#loadClass 失败原因探究 临时解决办法 验证是否成功 应用下新建Boss1类 自定义加载路径 ...

  3. (二)JVM成神路之剖析Java类加载子系统、双亲委派机制及线程上下文类加载器

    引言 上篇<初识Java虚拟机>文章中曾提及到:我们所编写的Java代码经过编译之后,会生成对应的class字节码文件,而在程序启动时会通过类加载子系统将这些字节码文件先装载进内存,然后再 ...

  4. JVM系列(三):双亲委派机制笔记

    今天给大家分享JVM系列之双亲委派机制相关的知识. 1.Java类加载的过程 Java类的加载过程是动态的,它不会一次性把程序所有的类全部加载后再运行,而是先保障程序运行的基础类加载到JVM虚拟机当中 ...

  5. 【JVM】类加载器:双亲委派机制、沙箱安全机制

    · 双亲委派机制.沙箱安全机制是JVM中类加载器系统的相关术语 · 在这之前,应该先了解JVM类加载器系统的相关概念 一.类加载器基础知识 见下图1,java文件首先会被编译成class文件,clas ...

  6. JVM学习笔记之-类加载子系统,类的加载与类的加载过程,双亲委派机制

    一 类加载器与类加载过程 类加载子系统作用 类加载器子系统负责从文件系统或者网络中加载class文件,class文件在文件开头有特定的文件标识. ClassLoader只负责class文件的加载,至于 ...

  7. 深入JVM系列(三)之类加载、类加载器、双亲委派机制与常见问题

    转载自 深入JVM系列(三)之类加载.类加载器.双亲委派机制与常见问题 一.概述 定义:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用 ...

  8. JVM学习笔记-03-类加载器及双亲委派机制

    JVM学习笔记-03-类加载器及双亲委派机制 文章目录 JVM学习笔记-03-类加载器及双亲委派机制 1. 类加载器 视频链接-最新JVM教程IDEA版[Java面试速补篇]-03-类加载器及双亲委派 ...

  9. JVM 学习四:类加载之双亲委派机制与沙箱安全机制

    1 双亲委派机制 Java 虚拟机对 Class 文件的加载采用的是按需加载的方式,也就是说:当需要使用该类时才会将它的 Class 文件加载到内存生成 Class 对象,而且加载某个类的 Class ...

  10. JVM 虚拟机类加载过程和双亲委派机制

    Java 编译后的字节码 Class 文件加载到虚拟机后才能运行和使用. 一.类加载过程 包括三个步骤, Loading 加载,Linking 链接,Initializing 初始化:第二步又可以细分 ...

最新文章

  1. QIIME 2教程. 19使用q2-vsearch聚类ASVs为OTUs(2020.11)
  2. Linux 系统启动流程及其介绍
  3. linux 查看线程数的方法
  4. Django配置开发环境和生产环境以及配置Jinja2模板引擎
  5. Lua === Lua 十分钟基础入门上手
  6. 【数据结构】线性表大咖
  7. PAT甲题题解-1011. World Cup Betting (20)-误导人的水题。。。
  8. word粘贴至html特殊字符 粘贴后可能为乱码
  9. OpenGL ES 3.2
  10. OpenCV Sobel和Scharr (索贝尔和夏尔滤波器检测边缘)
  11. laravel插入数据时报 502 Bad Gateway
  12. 网络工程师(软考)心得
  13. 计算机基础知识2003,计算机基础知识PPT2003练习题及答案(DOC)
  14. matlab计算并联电阻怎么输入,如何用计算器快速计算并联电阻,并联电阻的计算方法...
  15. MPS模块式柔性自动化生产线
  16. createrepo的用法
  17. 基于java+Mysql的志愿者管理系统代码分享
  18. 阿里云OSS获取文件强制下载的签名URL
  19. 什么是防火墙?服务器防火墙建议开启吗?
  20. 《淮南师范学院学报》(双月刊)投稿须知

热门文章

  1. 入职五年回顾(十四) 2013年9月
  2. Excel公式向导:文本数字转为日期格式的操作
  3. Apollo6.0代码Lattice算法详解——Part6:轨迹评估及碰撞检测对象构建
  4. DSP之TMS320F28335学习总结与笔记(三)————中断系统及其应用
  5. APN设置中界面显示及默认接入点配置
  6. 迟到的认可:计算机科学之父图灵将登50英镑新钞
  7. 云付通过银联认证了吗_查询pos设备是否通过银联安全认证的方法
  8. spring源码构建时缺失spring-cglib-repack.jar和spring-objenesis-repack.jar
  9. python - 在线答题程序
  10. CnOpenData中国各城市工商注册企业分年份数量统计(含新增,注销企业数量)