JVM - 彻底理解打破双亲委派机制
文章目录
- 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 - 彻底理解打破双亲委派机制相关推荐
- 【JVM】Java类的加载流程以及双亲委派,全盘托管,以及如何打破双亲委派机制
JVM基础生命周期流程图 只有main()方法的java程序执行流程 classLoader.loadClass()的类加载流程(除引导类,所有类都一样) 加载:通过IO查找读取磁盘上的字节码文件,在 ...
- JVM类加载机制、双亲委派机制、自定义类加载器、打破双亲委派机制
1.类加载器 站在Java虚拟机的角度看,只有两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),这个类加载器使用C++语言实现(HotSpot虚拟机.JDK8中), ...
- 如何打破双亲委派机制
双亲委派机制 第一次知道何为打破双亲委派机制是通过阅读周志明的<深入理解Java虚拟机>,我们知道双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器 ...
- JVM17_Tomcat打破双亲委派机制、执行顺序、底层代码原理、Tomcat|JDBC破坏双亲委派机制带来的面试题
文章目录 ①. Tomcat类加载机制 ②. Tomcat执行顺序 ③. ClassLoader的创建 ④. ClassLoader加载过程 ⑤. Tomcat破坏双亲委派机制带来的面试题 ①. To ...
- 【有料】面试必备:什么时候要打破双亲委派机制?什么是双亲委派? (图解+秒懂+史上最全)
面试题:什么时候要打破双亲委派机制 来自社群的两个面试题,其实也是两个基础的 面试题,大家一定要掌握 社群问题: 先说下第一题的结论 场景1: 如果委托类没有实现接口的话,就不能使用newProxyI ...
- 双亲委派机制以及打破双亲委派机制
双亲委派机制以及打破双亲委派机制 双亲委派机制 Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存中生成class对象,而且加载某个类的c ...
- 打破双亲委派机制有什么用_1.4 打破双亲委派机制
什么是打破双亲委派机制呢? 那么这里第一步, 我们需要知道什么是双亲委派机制? 前面已经说了什么是双亲委派机制了, 那打破是怎么回事呢? 比如, 我现在有一个自定义类加载器, 加载的是~/com/lx ...
- 如何打破双亲委派机制?
上文:jdk-Launcher源码学习 背景 上文说过,jdk是通过双亲委派机制实现类的加载,但是这个加载效率及场景存在弊端,所以本文借鉴tomcat的实现方式去打破双亲委派机制实现自定义类加载器来模 ...
- 面试必备:什么时候要打破双亲委派机制?什么是双亲委派? (图解+秒懂+史上最全)
文章很长,建议收藏起来慢慢读!疯狂创客圈总目录 语雀版 | 总目录 码云版| 总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 经典图书:<Java高并发核心编程(卷1)> 面试必备 ...
最新文章
- 14 个 Spring MVC 顶级技巧,随时用随时爽,一直用一直爽
- 张苗 清华大学 计算机,2011222229张苗组件局域网及搭建服务器技术分析.doc
- numpy-自定义ufunc函数和广播
- PHP 表单的提交完美示例
- Invalid signature file digest for Manifest main attributes
- SAP UI5 jQuery.sap.formatMessage
- 牛客题霸 转圈打印矩阵 C++题解/答案
- 模线性方程(中国剩余定理+扩展中国剩余定理)
- matlab chan算法定位,MATLAB实现基于Chan氏算法的三维TDOA定位
- android 按钮带图标 阴影_android中带图标的按钮(ImageButton)怎么用
- matlab+adst,SPC572L64E3 - 用于汽车动力系统应用的32位Power Architecture MCU - STMicroelectronics...
- 干货 | 我如何考察面试者的机器学习水平
- TLSF 内存分配算法详解
- 渗透工具TotalPass:TotalPass 是一款默认口令/弱口令扫描工具
- 等比数列和等差数列求和公式
- 2020年最好的机器人学仿真工具软件汇总
- 解答:为什么要搭建企业论坛?如何快速搭建?
- Tolua++技术文档
- 灵隐寺招聘:没有KPI、佛系上班、一切随缘
- 三、PyQt5高级控件的使用