双亲委派机制

第一次知道何为打破双亲委派机制是通过阅读周志明的《深入理解Java虚拟机》,我们知道双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器。每个类加载器都是如此,只有在父类加载器在自己的搜索范围内找不到指定类时,子类加载器才会尝试自己去加载。【这里的“父类”只是名义上的父类,而不是真的是继承上父子关系】
       这种模型要求,除了顶层的启动类加载器外,其他的类加载器都要有自己的父类加载器。假如有一个类要加载进来,一个类加载器并不会马上尝试自己将其加载,而是委派给父类加载器,父类加载器收到后又尝试委派给其父类加载器,以此类推,直到委派给启动类加载器,这样一层一层往上委派。只有当父类加载器反馈自己没法完成这个加载时,子加载器才会尝试自己加载。通过这个机制,保证了 Java 应用所使用的都是同一个版本的 Java 核心库的类,同时这个机制也保证了安全性。设想如果应用程序类加载器想要加载一个有破坏性的 java.lang.System 类,双亲委派模型会一层层向上委派,最终委派给启动类加载器,而启动类加载器检查到缓存中已经有了这个类,并不会再加载这个有破坏性的 System 类。
       另外,类加载器还拥有全盘负责机制,即当一个类加载器加载一个类时,这个类所依赖的、引用的其他所有类都由这个类加载器加载,除非在程序中显式地指定另外一个类加载器加载。
       在 Java 中,我们用完全匹配类名来标识一个类,即用包名和类名。而在 JVM 中,一个类由完全匹配类名和一个类加载器的实例 ID 作为唯一标识。也就是说,同一个虚拟机可以有两个包名、类名都相同的类,只要它们由两个不同的类加载器加载。当我们在 Java 中说两个类是否相等时,必须在针对同一个类加载器加载的前提下才有意义,否则,就算是同样的字节码,由不同的类加载器加载,这两个类也不是相等的。这种特征为我们提供了隔离机制,在 Tomcat 服务器中就使用到了这样的隔离机制。

在书中我们可以知道双亲委派模型破坏历史,以下是从书上摘抄下来

  1. 第一次破坏
           由于双亲委派模型是在JDK1.2之后才被引入的,而类加载器和抽象类java.lang.ClassLoader则在JDK1.0时代就已经存在,面对已经存在的用户自定义类加载器的实现代码,Java设计者引入双亲委派模型时不得不做出一些妥协。在此之前,用户去继承java.lang.ClassLoader的唯一目的就是为了重写loadClass()方法,因为虚拟机在进行类加载的时候会调用加载器的私有方法loadClassInternal(),而这个方法唯一逻辑就是去调用自己的loadClass()。
  2. 第二次破坏
           双亲委派模型的第二次“被破坏”是由这个模型自身的缺陷所导致的,双亲委派很好地解决了各个类加载器的基础类的同一问题(越基础的类由越上层的加载器进行加载),基础类之所以称为“基础”,是因为它们总是作为被用户代码调用的API,但世事往往没有绝对的完美。
    如果基础类又要调用回用户的代码,那该么办?
           一个典型的例子就是JNDI服务,JNDI现在已经是Java的标准服务,
    它的代码由启动类加载器去加载(在JDK1.3时放进去的rt.jar),但JNDI的目的就是对资源进行集中管理和查找,它需要调用由独立厂商实现并部署在应用程序的ClassPath下的JNDI接口提供者的代码,但启动类加载器不可能“认识”这些代码。
           为了解决这个问题,Java设计团队只好引入了一个不太优雅的设计:线程上下文类加载器(Thread Context ClassLoader)。这个类加载器可以通过java.lang.Thread类的setContextClassLoader()方法进行设置,如果创建线程时还未设置,他将会从父线程中继承一个,如果在应用程序的全局范围内都没有设置过的话,那这个类加载器默认就是应用程序类加载器。
           有了线程上下文加载器,JNDI服务就可以使用它去加载所需要的SPI代码,也就是父类加载器请求子类加载器去完成类加载的动作,这种行为实际上就是打通了双亲委派模型层次结构来逆向使用类加载器,实际上已经违背了双亲委派模型的一般性原则,但这也是无可奈何的事情。Java中所有涉及SPI的加载动作基本上都采用这种方式,例如JNDI、JDBC、JCE、JAXB和JBI等。
  3. 第三次破坏
           双亲委派模型的第三次“被破坏”是由于用户对程序动态性的追求导致的,这里所说的“动态性”指的是当前一些非常“热门”的名词:代码热替换、模块热部署等,简答的说就是机器不用重启,只要部署上就能用。
           OSGi实现模块化热部署的关键则是它自定义的类加载器机制的实现。每一个程序模块(Bundle)都有一个自己的类加载器,当需要更换一个Bundle时,就把Bundle连同类加载器一起换掉以实现代码的热替换。在OSGi幻境下,类加载器不再是双亲委派模型中的树状结构,而是进一步发展为更加复杂的网状结构,当受到类加载请求时,OSGi将按照下面的顺序进行类搜索:
    ① 将java.*开头的类委派给父类加载器加载。
    ② 否则,将委派列表名单内的类委派给父类加载器加载。
    ③ 否则,将Import列表中的类委派给Export这个类的Bundle的类加载器加载。
    ④ 否则,查找当前Bundle的ClassPath,使用自己的类加载器加载。
    ⑤ 否则,查找类是否在自己的Fragment Bundle中,如果在,则委派给Fragment Bundle的类加载器加载。
    ⑥ 否则,查找Dynamic Import列表的Bundle,委派给对应Bundle的类加载器加载。
    ⑦ 否则,类加载器失败。

jvm自带的三个类加载器所加载的路径如下

  • Bootstrap ClassLoader————jdk/jre/lib/ 目录下 Extension

  • ClassLoader————jdk/jre/lib/ext/ 目录下

  • Application ClassLoader————ClassPath路径下

双亲委派工作流程
①、当Application ClassLoader 收到一个类加载请求时,他首先不会自己去尝试加载这个类,而是将这个请求委派给父类加载器Extension ClassLoader去完成。
②、当Extension ClassLoader收到一个类加载请求时,他首先也不会自己去尝试加载这个类,而是将请求委派给父类加载器Bootstrap ClassLoader去完成。
③、如果Bootstrap ClassLoader加载失败(在<JAVA_HOME>\lib中未找到所需类),就会让Extension ClassLoader尝试加载。
④、如果Extension ClassLoader也加载失败,就会使用Application ClassLoader加载。
⑤、如果Application ClassLoader也加载失败,就会使用自定义加载器去尝试加载。
⑥、如果均加载失败,就会抛出ClassNotFoundException异常。

应用场景

那么那些地方会应用到打破双亲委派机制这样的情况呢?
答:

  1. SPI机制:对应双亲委派破坏使的第二次
    例如:
         ①JDBC加载不同类型的驱动模块:
          以DriverManager.class来说明。DriverManager的classloader是BootstrapClassLoader,而其得到的connection的classloader是ApplicationClassLoader。如果在A类引用B类时发现B类还没有加载,那么会调用A类的类加载器进行加载,并且由于可见性的原因,BootstrapClassLoader加载的类是看不到Extension ClassLoader或者ApplicationClassLoader加载的类的,这里对应的是DriverManager和connection。所以说SPI破坏了双亲委任模型。
         若还没理解的话我在详细解释一下,若按照双亲委任模型的话, DriverManager被Bootstrap类加载器加载,其内部引用到的connection也理应由Bootstrap类加载器加载,但Driver.class的实现类不在Bootstrap类加载器所能扫描到的范围里,所以交由Bootstrap类加载器是弄不了的,而双亲委任模型规定是先交由父类去加载,加载不了再由自己加载,而Bootstrap类加载器是最顶层的类加载器了,没有父类了,所以交由自己加载,但是自己也加载不了,所以为了能够加载到Driver.class的实现类,我们只能打破双亲委任模型了【使用子类加载器去加载Driver.class的实现类】,通过Thread.currentThread().getContextClassLoader()的方式,我们将得到ApplicationClassLoader,而ApplicationClassLoader就能够扫描到我们添加进来的jar包【依赖的jar包都是在ClassPath下】,所以Driver.class的实现类就能够被加载到。若仍然还未能理解的话,请看JDBC加载mysql驱动模块
  2. tomcat:在tomcat中,核心的Java类的加载还是遵从双亲委派模型的 ,而重点突出违反双亲委派模型的是:在Tomcat中各个web应用在加载类的时候会优先使用自己的类加载器(WebAppClassLoader),加载不到时再交给commonClassLoader走双亲委托 ,这就打破了双亲委派机制。
  3. 热部署:可以看上面双亲委派破坏史第三次

如何打破双亲委派机制相关推荐

  1. 【有料】面试必备:什么时候要打破双亲委派机制?什么是双亲委派? (图解+秒懂+史上最全)

    面试题:什么时候要打破双亲委派机制 来自社群的两个面试题,其实也是两个基础的 面试题,大家一定要掌握 社群问题: 先说下第一题的结论 场景1: 如果委托类没有实现接口的话,就不能使用newProxyI ...

  2. 双亲委派机制以及打破双亲委派机制

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

  3. Java打破双亲委派机制

    1.自定义加载器 沿用双亲委派机制自定义类加载器很简单,只需继承ClassLoader类并重写findClass方法即可. ①先定义一个待加载的类Test,它很简单,只是在构建函数中输出由哪个类加载器 ...

  4. 【JVM】Java类的加载流程以及双亲委派,全盘托管,以及如何打破双亲委派机制

    JVM基础生命周期流程图 只有main()方法的java程序执行流程 classLoader.loadClass()的类加载流程(除引导类,所有类都一样) 加载:通过IO查找读取磁盘上的字节码文件,在 ...

  5. 打破双亲委派机制有什么用_1.4 打破双亲委派机制

    什么是打破双亲委派机制呢? 那么这里第一步, 我们需要知道什么是双亲委派机制? 前面已经说了什么是双亲委派机制了, 那打破是怎么回事呢? 比如, 我现在有一个自定义类加载器, 加载的是~/com/lx ...

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

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

  7. 面试必备:什么时候要打破双亲委派机制?什么是双亲委派? (图解+秒懂+史上最全)

    文章很长,建议收藏起来慢慢读!疯狂创客圈总目录 语雀版 | 总目录 码云版| 总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 经典图书:<Java高并发核心编程(卷1)> 面试必备 ...

  8. JVM类加载机制、双亲委派机制、自定义类加载器、打破双亲委派机制

    1.类加载器 站在Java虚拟机的角度看,只有两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),这个类加载器使用C++语言实现(HotSpot虚拟机.JDK8中), ...

  9. Tomcat打破双亲委派机制

    打破双亲委派 沙箱安全机制示例,尝试打破双亲委派机制,用自定义类加载器加载自己实现的 java.lang.String.class public class MyClassLoaderTest {st ...

最新文章

  1. 分布式环境下的并发问题
  2. mysql引擎层存储层_MySQL存储底层技术:InnoDB底层原理解读
  3. 汇编语言介绍,内存和总线的初步认识
  4. EXECUTE IMMEDIATE用法小解
  5. cmake Debug模式和Release模式
  6. 从P560小型机B181201B故障代码识别手把手详解
  7. 京东云Ubuntu下安装mysql
  8. 「Mac新手必备」解决 Mac 无法启动、开机的问题
  9. VisualSVN-Server 安装以及使用教程
  10. linux 系统开启火狐命令_linux安装火狐命令
  11. 深度学习面试题之CNN
  12. java pdf添加页码_java itext pdf 怎么加页码
  13. 找手机ic库存回收公司
  14. 五脏积毒的表现 脸上长痘位置看你健康情况
  15. android 检测是否模拟器,Android全面检测设备是否模拟器
  16. 鸿蒙系统可以微信吗,鸿蒙系统可以用微信吗?微信鸿蒙版本下载-游戏大玩家...
  17. 使用etop工具监测Erlang运行环境
  18. 实现财务自由的重要工具
  19. 考研计算机专业学校选择,关于学校的选择问题:计算机专业_跨考网
  20. 使用RestFul风格操作ElasticSearch 看这篇够了

热门文章

  1. 将代码提交到github上
  2. 第一章 富爸爸,穷爸爸
  3. Android自定义Drawable第十四式之百步穿杨
  4. 揭秘虚拟化环境高可靠存储的构架和配置
  5. linux主机motd和命令审计
  6. ROS中没有/cmd_vel话题的解决办法
  7. Serenity框架官方文档翻译3.1(教程)
  8. python的基本文本处理操作
  9. #655 – 冒泡事件可能会被某些控件屏蔽(Bubbling Mouse Events Swallowed by Some Controls)
  10. python两张图片无缝合成一张,Python实现拼接多张图片的方法