当前位置: 首页 > news >正文

JVM面试(四)类加载器和双亲委派机制

什么是类加载器?

简单来说的话,是用于实现“类加载动作”的加载器
“通过一个类的全限定名来获取描述该类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需的类。实现这个动作的代码被称为“类加载器”(Class Loader)。

这里需要注意一个特点,对于任何一个类,都要根据这个类本身以及加载它的类加载器来共同确认其在Java虚拟机中的唯一性
有些拗口,但是希望各位同学能多念几遍理解一下。

从另一个角度来说,如果两类的名字相等,即使来自同一个.class文件,但是所用的类加载器不是同一个,虚拟机就不会认为是同一个类,是两个独立的类。

为什么需要双亲委派机制?

上面说了,不同类加载器加载出来的类,一定不相同。

所以,为了保护java底层本身的类不被篡改(比如java.lang.Object、java.lang.String)。
无论是在各种程序中,各种类加载器环境中都保证被同一个类加载器进行加载。
就是用双亲委派机制,全都委派给处于模型最顶端的启动类加载器进行加载。
如下图:
在这里插入图片描述

双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载。

其实代码也简单得很,如下:

protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{// 首先,检查请求的类是否已经被加载过了Class c = findLoadedClass(name);if (c == null) {try {if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// 如果父类加载器抛出ClassNotFoundException// 说明父类加载器无法完成加载请求}if (c == null) {// 在父类加载器无法加载时// 再调用本身的findClass方法来进行类加载c = findClass(name);}}if (resolve) {resolveClass(c);}return c;
}

破坏双亲委派机制

很好理解啊,加载类的时候不按照这个顺序APPClassLoader->Ext ClassLoader->BootStrap ClassLoader进行加载就算是打破了双亲委派机制呗。

比如tomcat,只要用过tomcat部署工程的都知道,我们是把项目打成war包,让在webapp文件夹下面,那么就意味着tomcat同时可以运行多个web程序。

那在多个项目里面就有可能存在相同名称和路径的类。为了防止他们不冲突,tomcat就给每个web应用都创建一个类加载器实例,WebAppClassLoader。
该类重写了loaderClass()方法,优先加载当前应用目录下的类,如果找不到了,再进入用双亲委派机制一层层寻找加载器。
这其实算是一个双亲委派机制的补丁。

还有一种情况,双亲委派机制本身的模型就是“越基础的类,越由上层加载器来加载”。 那么什么是“基础”类? 就是哪些总作为被继承、调用API存在的类。 但是,如果存在那种,既有基础类型,又要回调用户代码怎么办?

这里最典型的就是JDBC,JDBC定义类接口,但是实现类肯定是由各个厂商来实现的, 比如mysql。
我们使用jdbc的时候,通过DriverManager来获取connection链接的,明显DriverManager是基础类,由BootstrapClassLoader加载的。

但是在我们使用DriverManager.getConnection()的时候,获取的一定是数据库厂商的类,BootstrapClassLoader不可能加载到第三方厂商的类啊。
解决方案就是,DriverManager在初始化的时候获取「线程上下文加载器」(Thread Context ClassLoader),在获取connection的时候使用线程上下文加载器来加载connection,这里的线程上下文加载器实际上还是App ClassLoader。
所以在获取connection的时候先找ExtClassLoader和BootstrapClassLoader加载器,只不过这俩加载器肯定加载不到,最终还是由AppClassLoader来加载。

其实话说回来,这些也可以算作双亲委派机制的加强补丁,并不是“破坏”双亲委派机制。 仁者见仁智者见智吧

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 什么是敏捷?
  • Kafka【九】如何实现数据的幂等性操作
  • SQL各子句的执行顺序
  • 【Jupyter Notebook】汉化
  • 简单的springboot log4j2日志配置
  • 如何在实际应用中优化AI大模型性能
  • 学习大模型最佳书籍推荐:NUS尤洋教授所著新书《实战AI大模型》,得到李开复、颜水成、周鸿祎大牛鼎力推荐
  • 如何通过商品id商品链接来获取淘宝商品主图详情图等数据?
  • 828华为云征文 | 基于Docker与Jenkins实现自动化部署
  • 大模型推理--KV Cache
  • SCL 常见问题
  • 异常整理(JAVA基础)
  • 【C++】STL容器详解【上】
  • Java——堆
  • 路灯集中控制器与智慧照明:塑造未来城市的智能光影
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • Java 最常见的 200+ 面试题:面试必备
  • java多线程
  • ng6--错误信息小结(持续更新)
  • Puppeteer:浏览器控制器
  • VuePress 静态网站生成
  • vuex 笔记整理
  • Xmanager 远程桌面 CentOS 7
  • 创建一种深思熟虑的文化
  • 对象管理器(defineProperty)学习笔记
  • 聚类分析——Kmeans
  • 如何打造100亿SDK累计覆盖量的大数据系统
  • 使用Swoole加速Laravel(正式环境中)
  • 限制Java线程池运行线程以及等待线程数量的策略
  • 正则表达式
  • 正则表达式小结
  • 自定义函数
  • Java数据解析之JSON
  • 阿里云ACE认证学习知识点梳理
  • ​LeetCode解法汇总518. 零钱兑换 II
  • ‌JavaScript 数据类型转换
  • (1)svelte 教程:hello world
  • (4)STL算法之比较
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (二)Kafka离线安装 - Zookeeper下载及安装
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (六)软件测试分工
  • (三)uboot源码分析
  • (四)汇编语言——简单程序
  • (限时免费)震惊!流落人间的haproxy宝典被找到了!一切玄妙尽在此处!
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • (轉貼) 寄發紅帖基本原則(教育部禮儀司頒布) (雜項)
  • 、写入Shellcode到注册表上线
  • .NET Micro Framework初体验(二)
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...