首页
题库
公司真题
专项练习
面试题库
在线编程
面试
面试经验
AI 模拟面试
简历
求职
学习
基础学习课
实战项目课
求职辅导课
专栏&文章
竞赛
搜索
我要招人
发布职位
发布职位、邀约牛人
更多企业解决方案
AI面试、笔试、校招、雇品
HR免费试用AI面试
最新面试提效必备
登录
/
注册
加盐的可乐
腾讯_后端
发布于福建
关注
已关注
取消关注
@程序员世杰:
面试官:如何打破双亲委派机制?
哈喽,大家好🎉,我是世杰。欢迎大家关注我的公众号『程序员世杰』获取更多面试内容🎉🎉!本文我为大家介绍面试官经常考察的「双亲委派机制」面试连环call双亲委派机制是什么?如何打破双亲委派机制?JVM都有哪些类加载器?如何构造一个自定义类加载器?Tomcat的类加载机制?Spring的类加载机制Class.forName()和ClassLoader.loadClass()区别?在开始讲述之前简单回顾一下之前的类加载过程类加载过程:加载->连接->初始化。其中连接过程又分为:验证->准备->解析。具体内容大家可以看我上一篇关于类加载过程的详细介绍类加载器作用类加载器的主要作用就是加载 Java 类的字节码( .class 文件)到 JVM 中(在内存中生成一个代表该类的 Class 对象)。字节码可以是 Java 源程序(.java文件)经过 javac 编译得来,也可以是通过工具动态生成或者通过网络下载得来。需要注意的是类加载器是一个负责加载类的对象,用于实现类加载过程中的加载这一步。每个 Java 类都有一个引用指向加载它的 ClassLoader。数组类不是通过 ClassLoader 创建的(数组类没有对应的二进制字节流),是由 JVM 直接生成的。Class.forName()和ClassLoader.loadClass()区别?Class.forName(): 将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块ClassLoader.loadClass(): 只是将.class文件加载到jvm中,不会执行static中的内容, 只有在newInstance才会去执行static中内容类加载器分类启动类加载器: Bootstrap ClassLoader,负责加载存放在JDK\jre\lib(JDK代表JDK的安装目录,下同)下,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库(如rt.jar,所有的**java.开头的类均被Bootstrap ClassLoader加载*)。启动类加载器是无法被Java程序直接引用的。扩展类加载器: Extension ClassLoader,该加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载JDK\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库(*如javax.开头的类),开发者可以直接使用扩展类加载器。应用程序类加载器: Application ClassLoader,该类加载器由sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。应用程序都是由这三种类加载器互相配合进行加载的,如果有必要,我们还可以加入自定义的类加载器。🌈 拓展一下:rt.jar:rt 代表“RunTime”,rt.jar是 Java 基础类库,包含 Java doc 里面看到的所有的类的类文件。也就是说,我们常用内置库 java.xxx.*都在里面,比如java.util.*、java.io.*、java.nio.*、java.lang.*、java.sql.*、java.math.*。Java 9 引入了模块系统,并且略微更改了上述的类加载器。扩展类加载器被改名为平台类加载器(platform class loader)。Java SE 中除了少数几个关键模块,比如说 java.base 是由启动类加载器加载之外,其他的模块均由平台类加载器所加载。双亲委派机制定义如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终会传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子类加载器才会尝试自己去加载该类。这种类加载器之间的层次关系被称为类加载器的“双亲委派模型(Parents Delegation Model)”。为什么要使用?防止内存中出现多份同样的字节码。如果没有该机制而是由各个类加载器自行加载的话,用户编写了一个java.lang.Object的同名类并放在ClassPath中,多个类加载器都能加载这个类到内存中,系统中将会出现多个不同的Object类,那么类之间的比较结果及类的唯一性将无法保证,同时,也会给虚拟机的安全带来隐患。双亲委派机制能够保证多加载器加载某个类时,最终都是由一个加载器加载,确保最终加载结果相同。这样可以保证系统库优先加载,即便是自己重写,也总是使用Java系统提供的System,自己写的System类根本没有机会得到加载,从而保证安全性。注意 ⚠️:双亲委派模型并不是一种强制性的约束,只是 JDK 官方推荐的一种方式。如果我们因为某些特殊需求想要打破双亲委派模型执行流程双亲委派模型的实现代码非常简单,逻辑非常清晰,都集中在 java.lang.ClassLoader 的 loadClass() 中,相关代码如下所示。protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{ synchronized (getClassLoadingLock(name)) { //首先,检查该类是否已经加载过 Class c = findLoadedClass(name); if (c == null) { //如果 c 为 null,则说明该类没有被加载过 long t0 = System.nanoTime(); try { if (parent != null) { //当父类的加载器不为空,则通过父类的loadClass来加载该类 c = parent.loadClass(name, false); } else { //当父类的加载器为空,则调用启动类加载器来加载该类 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { //非空父类的类加载器无法找到相应的类,则抛出异常 } if (c == null) { //当父类加载器无法加载时,则调用findClass方法来加载该类 //用户可通过覆写该方法,来自定义类加载器 long t1 = System.nanoTime(); c = findClass(name); //用于统计类加载器相关的信息 sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { //对类进行link操作 resolveClass(c); } return c; }}自定义类加载器构造自定义加载器,需要继承 ClassLoader 。如果我们不想打破双亲委派模型,就重写 ClassLoader 类中的 findClass() 方法即可,无法被父类加载器加载的类最终会通过这个方法被加载。但是,如果想打破双亲委派模型则需要重写 loadClass() 方法。不破坏双亲委派实现自定义类加载器的实现,主要分三个步骤创建一个类继承ClassLoader抽象类重写findClass()方法在findClass()方法中调用defineClass()public class MyClassLoader extends ClassLoader { private String classPath; public MyClassLoader(String classPath) { this.classPath = classPath; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { try { byte[] bytes = getClassBytes(name); Class<?> c = this.defineClass(name, bytes, 0, bytes.length); return c; } catch (Exception e) { e.printStackTrace(); } return super.findClass(name); } private byte[] getClassBytes(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; }}破坏双亲委派定义CoderWorldClass.java文件,并使用javac编译成.class文件public class CoderWorldClass { public CoderWorldClass(){ System.out.println("CoderWorldClass:"+getClass().getClassLoader()); System.out.println("CoderWorldClass Parent:"+getClass().getClassLoader().getParent()); } public String print(){ System.out.println("CoderWorldClass method for print NEW"); //修改了打印语句,用来区分被加载的类 return "CoderWorldClass.print()"; }}在MyClassLoader类中,重写loadClass方法,代码如下@Overrideprotected 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) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); //非自定义的类还是走双亲委派加载 if (!name.equals("CoderWorldClass")) { c = this.getParent().loadClass(name); } else { //自己写的类,走自己的类加载器。 c = findClass(name); } // this is the defining class loader; record the stats sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } if (resolve) { resolveClass(c); } return c; }}通过重写loadClass方法,使得自己创建的类,让第一个加载器直接加载,不委托父加载器寻找,从而实现双亲委派的破坏Tomcat类加载Tomcat是如何实现应用jar包的隔离的?在思考这个问题之前,我们先来想想Tomcat作为一个JSP/Servlet容器,它应该要解决什么问题?一个web容器需要部署多个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。部署在同一个web容器中相同的类库相同的版本可以共享。否则,如果服务器有10个应用程序,那么要有10份相同的类库加载进虚拟机,必然会带来内存消耗过高的问题。web容器也有自己依赖的类库,不能与应用程序的类库混淆。基于安全考虑,应该让容器的类库和程序的类库隔离开。Tomcat类加载机制Common类加载器作为 Catalina类加载器 和 Shared类加载器 的父加载器。Common类加载器 能加载的类都可以被 Catalina类加载器 和 Shared类加载器 使用。因此,Common类加载器 是为了实现公共类库(可以被所有 Web 应用和 Tomcat 内部组件使用的类库)的共享和隔离。Catalina类加载器 和 Shared类加载器 能加载的类则与对方相互隔离。Catalina类加载器 用于加载 Tomcat 自身的类,为了隔离 Tomcat 本身的类和 Web 应用的类。Shared类加载器 作为 WebApp类加载器 的父加载器,专门来加载 Web 应用之间共享的类比如 Spring、Mybatis。每个 Web 应用都会创建一个单独的 WebApp类加载器,并在启动 Web 应用的线程里设置线程线程上下文类加载器为 WebAppClassLoader,各个 WebAppClassLoader 实例之间相互隔离,进而实现 Web 应用之间的类隔。Tomcat如何破坏双亲委派?假设 Tomcat 服务器加载了一个 Spring Jar 包。项目中用到的基础类库,由于其是 Web 应用之间共享的,因此会由 SharedClassLoader 加载。项目中一些用到了 Spring 的业务类,比如实现了 Spring 提供的接口、用到了 Spring 提供的注解。所以,加载 Spring 的类加载器(也就是 SharedClassLoader)也会用来加载这些业务类。但是业务类在 Web 应用目录下,不在 SharedClassLoader 的加载路径下,所以 SharedClassLoader 无法找到业务类,也就无法加载它们。如何解决这个问题呢?这个时候就需要用到 线程上下文类加载器(ThreadContextClassLoader) 。当 Spring 需要加载业务类的时候,它不是用自己的类加载器,而是用当前线程的上下文类加载器。还记得我上面说的吗?每个 Web 应用都会创建一个单独的 WebAppClassLoader,并在启动 Web 应用的线程里设置线程线程上下文类加载器为 WebAppClassLoader。这样就可以让高层的类加载器(SharedClassLoader)借助子类加载器( WebAppClassLoader)来加载业务类,从而破坏了 Java 类加载的双亲委托机制。参考内容十分钟搞懂Java类加载Java 类加载机制类加载器详解(重点)类加载器请你简单说一下类加载机制的实现原理?
点赞 5
评论 0
全部评论
推荐
最新
楼层
暂无评论,快来抢首评~
相关推荐
05-02 21:33
蚌埠坦克学院 嵌入式软件开发
我觉得最好用的AI编程工具是codex
我觉得目前最好用的 AI 编程工具是 OpenAI Codex。相比传统的代码补全工具,它更像一个“可以接任务的 AI 工程师”,不仅能写代码,还能理解项目结构、修复 Bug、生成测试,甚至直接参与完整的软件开发流程。在实际使用中,Codex 的优势主要体现在效率和完整性上。你只需要描述需求,它就可以从实现功能到调试优化一并完成,大幅减少重复劳动。同时,它支持在终端、编辑器和云端多种环境中使用,还能并行处理多个任务,让开发节奏明显加快。总体来说,Codex 已经不只是“辅助工具”,而是正在改变编程方式的生产力工具。对于开发者来说,用好它,本质上是在学会如何和一个高效的“AI搭档”协作。
你觉得最好用的AI编程工...
点赞
评论
收藏
分享
昨天 23:10
门头沟学院 算法工程师
各位亦菲彦祖帮忙选选offer
主包当前只拿到了两个算法offer:一个是拼多多的算法实习生一个是荣耀的大模型算法实习生当前犹豫点在于:- 不知道pdd进去之后是做什么方向算法- 有点担心让做搜推相关的算法,我对搜推完全是零经验- 更想做和大模型相关的工作,但是荣耀实习的含金量没有pdd强求求各位佬给点建议有没有哪位佬比较了解pdd算法实习的工作内容的,一般是做什么方向的算法
点赞
评论
收藏
分享
03-30 12:34
江南大学 Java
27届找实习,心灰意冷
各位大佬请给点建议,我最近感觉好焦虑,有想放弃的想法😭
27届求职交流
点赞
评论
收藏
分享
04-23 13:28
上海海洋大学 数据分析师
26应届生0offer
至今一个可转正被割了剩下的5点面试都挂了求收留,数据分析,数据开发,测试!
点赞
评论
收藏
分享
04-30 22:09
The University of Sheffield 运营
大家好,我是一名跨境电商运营,有将近一年全链路实战经验,在牛客潜水很久了,鼓起勇气发一帖求内推,希望
求内推】上财+谢菲尔德硕士|跨境电商运营1年|求供应链/运营/BD大厂外企大家好,我是一名跨境电商运营,有将近一年全链路实战经验,在牛客潜水很久了,鼓起勇气发一帖求内推,希望有缘人看到!📌 基本情况本科:上海财经大学 · 国际理财硕士:英国谢菲尔德大学(Russell Group)· 应用经济学英语:雅思7.5 / PTE 77,日常工作沟通无压力求职地:深圳📌 实战经历独立负责OZON、Wildberries、Mercado Libre三个平台从0到1搭建,覆盖工业品、电动工具、手机配件、汽车导航等多品类。管过200+供应商渠道,对接过俄罗斯、巴西、墨西哥本土物流,单店月GMV做到7万美...
我是XXX,请攻击我最薄...
点赞
评论
收藏
分享
评论
点赞成功,聊一聊 >
1
收藏
分享
评论
提到的真题
返回内容
全站热榜
更多
1
...
agent开发是测试的最好转型期
7111
2
...
学院本拿下字节暑期offer!!!
6981
3
...
快手后端一面面经
5932
4
...
一位小镇做题家的自白
4581
5
...
后端开发简历求拷打
4420
6
...
至今,暑假实习0offer
3989
7
...
27届UE游戏客户端暑期结束力,小小地做个总结吧
3989
8
...
九本实习率
2758
9
...
面试真题】美团Agent 方向面经整理
2532
10
...
校招offer高压内耗,求大佬建议
2375
创作者周榜
更多
正在热议
更多
#
如果春招能重来,我会___
#
24619次浏览
256人参与
#
刚入职就____,这样正常吗?
#
144898次浏览
696人参与
#
在爱玛,骑向未来
#
15965次浏览
344人参与
#
这个offer值得去吗?
#
24338次浏览
192人参与
#
有深度的简历长什么样?
#
59311次浏览
758人参与
#
你会因为行情,降低找工作标准吗?
#
37826次浏览
300人参与
#
联宝杯大学生创新大赛,你的技术值得产业级答案
#
48467次浏览
585人参与
#
字节开奖
#
154301次浏览
730人参与
#
面试常问题系列
#
307162次浏览
4797人参与
#
上班苦还是上学苦呢?
#
345959次浏览
2076人参与
#
实习怎么做才有更好的产出
#
50377次浏览
462人参与
#
你见过最离谱的招聘要求是什么?
#
281298次浏览
1887人参与
#
大学四年该怎么过,才不算浪费时间?
#
24078次浏览
108人参与
#
字节求职进展汇总
#
1852730次浏览
15454人参与
#
今年形式下双非本找得到工作吗
#
329241次浏览
1776人参与
#
双非应该如何逆袭?
#
590150次浏览
6421人参与
#
我的秋招“寄”录
#
476823次浏览
3065人参与
#
薪资爆料
#
423635次浏览
2228人参与
#
秋招想进国企该如何准备
#
146926次浏览
687人参与
#
影石Insta360求职进展汇总
#
190544次浏览
1386人参与
#
双非本科求职如何逆袭
#
1652981次浏览
13109人参与
#
简历上的经历如何包装
#
294350次浏览
4123人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务