文章目录

  • Pre 双亲委派
  • 何为打破双亲委派
  • 如何打破双亲委派
  • 演示
    • 重写 ClassLoader#loadClass
    • 失败原因探究
    • 临时解决办法
    • 验证是否成功
      • 应用下新建Boss1类
      • 自定义加载路径D:/artisan/com/gof/facadePattern下保留Boss1.class
      • 验证
        • 输出结果

Pre 双亲委派

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

JVM - 自定义类加载器


何为打破双亲委派

举个例子 有个类 Artisan

我们希望通过自定义加载器 直接从某个路径下读取Artisan.class . 而不是说 通过自定义加载器 委托给 AppClassLoader ------> ExtClassLoader ----> BootClassLoader 这么走一遍,都没有的话,才让自定义加载器去加载 Artisan.class . 这么一来 还是 双亲委派。

我们期望的是 Artisan.class 及时在 AppClassLoader 中存在,也不要从AppClassLoader 去加载。

说白了,就是 直接让自定义加载器去直接加载Artisan.class 而不让它取委托父加载器去加载,不要去走双亲委派那一套。

我们知道 双亲委派的机制是在ClassLoader # loadClass方法中实现的,打破双亲委派,那我们是不是可以考虑从这个地方下手呢?


如何打破双亲委派

核心: 重写ClassLoader#loadClass方法


演示

刚才的思路是对的,要打破它,那就搞loadClass方法。

重写loadClass方法呗。

我们基于 JVM - 自定义类加载器 再来搞一搞

需要再此基础上 重写loadClass 方法

回归下双亲委派的源码

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) {c = parent.loadClass(name, false);} else { //如果当前加载器父加载器为空则委托引导类加载器加载该类c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {}if (c == null) {// If still not found, then invoke findClass in order// to find the class.long t1 = System.nanoTime();//调用URLClassLoader的findClass方法在加载器的类路径里查找并加载该类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;}}

那打破它,那我们就不要委托父加载器了呗,直接去findClass 不就好了?

我们把loadClass方法的源码copy过来 把双亲委派的部分代码去掉吧,走 改下

重写 ClassLoader#loadClass


public class MyClassLoaderTest {static class MyClassLoader extends ClassLoader {private String classPath;public MyClassLoader(String classPath) {this.classPath = classPath;}private byte[] loadByte(String name) throws Exception {name = name.replaceAll("\\.", "/");FileInputStream fis = new FileInputStream(classPath + "/" + name+ ".class");int len = fis.available();byte[] data = new byte[len];fis.read(data);fis.close();return data;}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) {c = findClass(name);}if (resolve) {resolveClass(c);}return c;}}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {try {byte[] data = loadByte(name);//defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组。return defineClass(name, data, 0, data.length);} catch (Exception e) {e.printStackTrace();throw new ClassNotFoundException();}}}

重点

   protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// 尝试加载,不存在直接去findClass ,不走委托父类Class<?> c = findLoadedClass(name);if (c == null) {c = findClass(name);}if (resolve) {resolveClass(c);}return c;}}

运行下


失败原因探究

略微尴尬, Object.class 找不到 。 为啥 呢? 你加载Boss1的时候, Boss1的父类也需要被加载, 你又把双亲委派给关了, 这个自定义的加载器在本地路径下是找不到Object.class的 。

咋办? 放到自定义的加载器加载的路径下 ?

-----> 其实是不行的,Object 谁能篡改的了啊 ,Object只能由引导类加载器来加载。

临时解决办法

所以换个思路 ,自己的类路径下的对象走我自己的classLoader, 其他的类 还是走双亲委派

 if ("com.gof.facadePattern.Boss1".equals(name)){c = findClass(name);}else{// 交由父加载器去加载c = this.getParent().loadClass(name);}

验证是否成功

这个时候我们在AppClassLoader加载的路径下 再创建个Boss1 (如果走的还是双亲委派,那加载器肯定还是AppClassLoader)

看 是不是这个Boss1 还是被自定义的ClassLoader加载,如果是,说明打破成功。

应用下新建Boss1类

自定义加载路径D:/artisan/com/gof/facadePattern下保留Boss1.class

验证

输出结果

OK,双亲委派机制 打破成功。

这个在tomcat类加载机制中非常重要,所以需要彻底明白这一点。

JVM - 彻底理解打破双亲委派机制相关推荐

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

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

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

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

  3. 如何打破双亲委派机制

    双亲委派机制 第一次知道何为打破双亲委派机制是通过阅读周志明的<深入理解Java虚拟机>,我们知道双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器 ...

  4. JVM17_Tomcat打破双亲委派机制、执行顺序、底层代码原理、Tomcat|JDBC破坏双亲委派机制带来的面试题

    文章目录 ①. Tomcat类加载机制 ②. Tomcat执行顺序 ③. ClassLoader的创建 ④. ClassLoader加载过程 ⑤. Tomcat破坏双亲委派机制带来的面试题 ①. To ...

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

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

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

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

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

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

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

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

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

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

最新文章

  1. 14 个 Spring MVC 顶级技巧,随时用随时爽,一直用一直爽
  2. 张苗 清华大学 计算机,2011222229张苗组件局域网及搭建服务器技术分析.doc
  3. numpy-自定义ufunc函数和广播
  4. PHP 表单的提交完美示例
  5. Invalid signature file digest for Manifest main attributes
  6. SAP UI5 jQuery.sap.formatMessage
  7. 牛客题霸 转圈打印矩阵 C++题解/答案
  8. 模线性方程(中国剩余定理+扩展中国剩余定理)
  9. matlab chan算法定位,MATLAB实现基于Chan氏算法的三维TDOA定位
  10. android 按钮带图标 阴影_android中带图标的按钮(ImageButton)怎么用
  11. matlab+adst,SPC572L64E3 - 用于汽车动力系统应用的32位Power Architecture MCU - STMicroelectronics...
  12. 干货 | 我如何考察面试者的机器学习水平
  13. TLSF 内存分配算法详解
  14. 渗透工具TotalPass:TotalPass 是一款默认口令/弱口令扫描工具
  15. 等比数列和等差数列求和公式
  16. 2020年最好的机器人学仿真工具软件汇总
  17. 解答:为什么要搭建企业论坛?如何快速搭建?
  18. Tolua++技术文档
  19. 灵隐寺招聘:没有KPI、佛系上班、一切随缘
  20. 三、PyQt5高级控件的使用

热门文章

  1. SAP help使用和下载官方文档教程
  2. redis中Zset数据类型最全常用命令
  3. Python 将关系对数据转换为图数据 / 邻接矩阵
  4. Apple App Store 音乐App 美国畅销榜单前30名使用记录
  5. 学习Linux是存在捷径的
  6. nyoj144 小珂的苦恼
  7. 每日一记 - 3.6
  8. 蚁视牵手联创互联,可持续拓展“第六媒体”新业态
  9. Docker学习1——Docker入门
  10. Redis 集群规范(MOVED错误码及ASK错误码)