双亲委派机制

定义

如果一个类加载器在接到加载类的请求时,它首先不会自己尝试去加载这个类,而是把这个请求任务委托给父类加载器去完成,依次递归,如果父类加载器可以完成类加载任务,就成功返回。只有父类加载器无法完成此加载任务时,才自己去加载。

加载器的分类

  • 除了顶层的启动类加载器外,其余的类加载器都应当有自己的“父类”加载器。

  • 不同类加载器看似是继承(Inheritance) 关系,实际上是包含关系。在下层加载器中,包含着上层加载器的引用

本质

规定了类加载的顺序是:引导类加载器先加载,若加载不到,由扩展类加载器加载,若还加载不到,才会由系统类加载器或自定义的类加载器进行加载。

双亲委派机制优势与劣势

双亲委派机制优势

  • 避免类的重复加载,确保一个类的全局唯一性。

    Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子classLoader再加载一次。

  • 保护程序安全,防止核心API被随意算改

    如果定义一个和String相同包的类java.lang.String,在运行时会抛出java.lang.SecurityException异常,起到了保护核心API的作用。

双亲委派机制劣势

检查类是否加载的委托过程是单向的,这个方式虽然从结构上说比较清晰,使各个ClassLoader的职责非常明确,但是同时会带来一个问题,即顶层的ClassLoader无法访问底层的ClassLoader所加载的类

通常情况下,启动类加载器中的类为系统核心类,包括一些重要的系统接口,而在应用类加载器中,为应用类。按照这种模式,应用类访问系统类自然是没有问题,但是系统类访问应用类就会出现问题。比如在系统类中提供了一个接口,该接口需要在应用类中得以实现,该接口还绑定一个工厂方法,用于创建该接口的实例,而接口和工厂方法都在启动类加载器中。这时,就会出现该工厂方法无法创建由应用类加载器加载的应用实例的问题。

源码逻辑

双亲委派机制在java.lang.ClassLoader.loadClass(String,boolean)接口中体现。该接口的逻辑如下:

(1)先在当前加载器的缓存中查找有无目标类,如果有,直接返回。

(2)判断当前加载器的父加载器是否为空,如果不为空,则调用parent.loadclass(name,false)接口进行加载。

(3)反之,如果当前加载器的父类加载器为空,则调用findBootstrapclassOrNull(name)接口,让引导类加载器进行加载。

(4)如果通过以上3条路径都没能成功加载,则调用findclass(name)接口进行加载。该接口最终会调用java.lang.ClassLoader接口的

defineClass系列的native接口加载目标Java类。双亲委派的模型就隐藏在这第2和第3步中。

源码实现

抽象类classLoader的主要方法:

1. loadClass方法

protected Class<?> loadClass(String name, boolean resolve)

加载名称为name的类,返回结果为java.lang.class类的实例。如果找不到类,则返回 CassNotFoundException异常。该方法中的逻辑就是双亲委派模式的实现。

protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException
{synchronized (getClassLoadingLock(name)) {     //同步操作,保证只能加载一次// First, check if the class has already been loaded//在缓存中判断是否已经加载同名的类Class<?> c = findLoadedClass(name);if (c == null) {long t0 = System.nanoTime();try {//获取当前类加载器的父类加载器if (parent != null) {//如果存在父类加载器,则调用父类加载器进行类加载,父类加载器再次调用loadClass方法,类似于递归操作。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) {//加载类c = findClass(name);}}if (resolve) {resolveClass(c);}return c;}
}

2. findeClass方法

如果需要重写,官方建议重写此方法(findClass),仍然能满足双亲委派机制,而不是重写loadClass方法。

protected Class<?> findClass(String name)

查找二进制名称为name的类,返回结果为java.lang.class类的实例。这是一个受保护的方法,JVM鼓励我们重写此方法,需要自定义加载器遵循双亲委托机制,该方法会在检查完父类加载器之后被loadclass()方法调用。

URLClassLoader类中找到此方法的重写。

protected Class<?> findClass(final String name) //name:需要被实例化类的路径名throws ClassNotFoundException
{final Class<?> result;try {result = AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() {public Class<?> run() throws ClassNotFoundException {//处理类路径String path = name.replace('.', '/').concat(".class");Resource res = ucp.getResource(path, false);if (res != null) {try {//生成class实例return defineClass(name, res);} catch (IOException e) {throw new ClassNotFoundException(name, e);} catch (ClassFormatError e2) {if (res.getDataError() != null) {e2.addSuppressed(res.getDataError());}throw e2;}} else {return null;}}}, acc);} catch (java.security.PrivilegedActionException pae) {throw (ClassNotFoundException) pae.getException();}if (result == null) {throw new ClassNotFoundException(name);}return result;
}

defineClass方法,生成class实例,

根据给定的字节数组b转换为Class的实例,off和len参数表示实际class信息在byte数组中的位置和长度,其中byte数组b是classLoader从外部获取的。这是受保护的方法,只有在自定义classLoader子类中可以使用.

private Class<?> defineClass(String name, Resource res)

破坏双亲委派机制----线程上下文类加载器

双亲委派模型的第二次“被破坏”是由这个模型自身的缺陷导致的,双亲委派很好地解决了各个类加载器协作时基础类型的一致性问题(越基础的类由越上层的加载器进行加载》,基础类型之所以被称为“基础”,是因为它们总是作为被用户代码继承、调用的API存在,但程序设计往往没有绝对不变的完美规则,如果有基础类型又要调用回用户的代码,那该怎么办呢?

这并非是不可能出现的事情,一个典型的例子便是JNDI服务,JNDI现在已经是Java的标准服务,它的代码由启动类加载器来完成加载(在JDK 1.3时加入到rt.jar的),肯定属于Java中很基础的类型了。但JNDI存在的目的就是对资源进行查找和集中管理,它需要调用由其他厂商实现并部署在应用程序的ClassPath下的JNDI服务提供者接口(Service Provider Interface,SPI)的代码,现在问题来了,启动类加载器是绝不可能认识、加载这些代码的,那孩怎么办?SPI:在Java平台中,通常把核心类rt.ar中提供外部服务、可由应用层自行实现的接口称为SPI)
为了解决这个困境,Java的设计团队只好引入了一个不太优雅的设计: 线程上下文类加载器 (Thread ContextlassLoader)。这个类加载器可以通过iava,lang,Thread类的setContextClassLoader()方法进行设置,如果创建线程时还未设置,它将会从父线程中继承一个,如果在应用程序的全局范围内都没有设置过的话,那这个类加载器默认就是应用程序类加载器。

默认上下文加载器就是应用类加载器,这样以上下文加载器为中介,使得启动类加载器中的仅码也可以访问应用类加载
器中的类。

简单来说就是线程上下文类加载器让启动类加载器和系统类加载器直接联系起来了,中间的扩展类加载器被省略了,所以这破坏了双亲委派机制,其中线程上下文类加载器就是系统类加载器,这个证明在01-概述—>载器之间的关系中有解释

详解JVM之双亲委派机制相关推荐

  1. 浅谈JVM的双亲委派机制

    双亲委派机制的含义 JAVA的类加载器分类 一共有四种: 启动类加载器 扩展类加载器 应用程序加载器 自定义加载器 定义 JVM通过双亲委派机制对类进行加载.双亲委派机制指一个类在收到类加载请求后不会 ...

  2. 【JVM】jvm的双亲委派机制

    双亲委派机制 一.JVM体系结构 二.双亲委派机制的含义 三.双亲委派机制的源代码 四.双亲委派机制的意义 五.示例代码 一.JVM体系结构 我们先在这里放一张 JVM 的体系架构图,方便我们有个总体 ...

  3. 彻底弄懂类加载和JVM的双亲委派机制

    类加载 类的生命周期会经历以下 7 个阶段: 加载阶段(Loading) 验证阶段(Verification) 准备阶段(Preparation) 解析阶段(Resolution) 初始化阶段(Ini ...

  4. 【JVM】双亲委派机制详解

    通过上篇文章我们学习了类加载,也提到了因为双亲委派机制的存在自定义类加载器的实现,不要去覆盖ClassIoader类的loadClass方法,去实现findClass方法,接下来详细解释一下双亲委派机 ...

  5. (JVM)双亲委派机制 破坏双亲委派机制

    1. 双亲委派机制 类加载器用来把类加载到Java虚拟机中.从JDK1.2版本开始,类的加载过程采用双亲委派机制,这种机制能更好地保证Java平台的安全. Java 虚拟机对 class 文件采用的是 ...

  6. 【JVM】 双亲委派机制

    今日鸡汤:不学原理或许可以走的很快,但是学了原理会帮我们走的更远 - 一.前言 我们点击运行,然后我们的 Java 代码就会被编译器编译成 .class 字节码文件,然后我们的 .class 字节码文 ...

  7. 如何打破双亲委派机制?

    上文:jdk-Launcher源码学习 背景 上文说过,jdk是通过双亲委派机制实现类的加载,但是这个加载效率及场景存在弊端,所以本文借鉴tomcat的实现方式去打破双亲委派机制实现自定义类加载器来模 ...

  8. 【04-JVM面试专题-什么是双亲委派机制(父类委托机制)?如何打破双亲委派机制?双亲委派机制的优缺点?什么是沙箱安全机制呢?】

    什么是双亲委派机制?如何打破双亲委派机制? JVM的双亲委派机制知道吗?怎么打破它呢?你看看自己掌握的怎么样呢? 什么是双亲委派机制?(父类委托机制) 检查某个类是否已经加载 自底向上,从Custom ...

  9. JVM(1)之JVM的组成详解(字符串常量池+双亲委派机制+JIT即时编译......)

    以下总结自:<深入理解java虚拟机> + 宋红康老师视频 字节码文件介绍:深入理解JVM之Java字节码(.class)文件详解_Windy_729的博客-CSDN博客_字节码文件 JV ...

最新文章

  1. Spring Boot 3.0 M1 发布,正式弃用 Java 8,最低要求 Java 17。。。
  2. 采集网站特殊文件Meta信息
  3. Delphi_04_Delphi_Object_Pascal_基本语法_02
  4. 图像理解之物体检测object detection,模型rcnn/fastrcnn/fasterrcnn原理及概念
  5. android文章链接
  6. Spring Cloud Gateway(限流)
  7. 计算机管理游戏,网吧游戏管理系统
  8. mySQL危险命令_MYSQL教程Linux系统中最危险的10条命令
  9. rgbdslam_v2编译过程中引起的needed by错误
  10. poj 2777 Count Color 基础线段树,带给的初学者噩梦!!!
  11. python面向对象设计角色攻击_Python技能:面向对象基础实战之英雄联盟
  12. 自动控制原理5.1---频率特性
  13. java web学习心得
  14. 集合的三种遍历方式/集合的嵌套/产生任意范围内的随机数
  15. 联想笔记本键盘排线_笔记本键盘排线怎么拆 thinkpad
  16. OSChina 周六乱弹 —— 召唤养我的富婆
  17. 推荐几个最值得关注的可以投稿赚钱的微信公众号
  18. 视频截取并提取成音频
  19. 【IOS】IOS工程自动打包并发布脚本实现
  20. 计算机Excel怎么弄迷你图,excel怎么制作迷你图 excel迷你图的使用技巧

热门文章

  1. Python自动化脚本:清空回收站的内容
  2. CentOS 7下载地址(ISO文件)安装
  3. 【四二学堂】jquery方式ajax获取数据并渲染页面
  4. uva122Treea on the leval(二叉树遍历)
  5. 【语音算法】使用端点检测和百度语音识别技术实现视频的字幕生成
  6. Linux磁盘挂载和共享
  7. SABER 最强大的数模混合信号仿真软件
  8. visual studio 2013和visual studio 2015下载链接 老版本VS
  9. 设计模式 -- 状态模式
  10. rolling用法实例