首页
题库
公司真题
专项练习
面试题库
在线编程
面试
面试经验
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
全部评论
推荐
最新
楼层
暂无评论,快来抢首评~
相关推荐
昨天 11:21
已编辑
门头沟学院 算法工程师
在携程的一天
早上10点到岗,晚上7点走,中间干了啥?我是旅游BG的大模型算法工程师,今天带你看点不一样的。 10:00|到公司,先看一眼模型跑得怎么样工位上打开电脑,第一件事:登录训练平台,看看昨晚提交的视频生成任务跑完了没。还行,没有爆显存,Loss曲线正常。同事路过:“新模型效果咋样?”——“还在调,中午给你看demo。”10:30|晨会,聊15分钟旅游BU的晨会很快:对齐进度、同步卡点、确认优先级。我上周接了个AIGC视频生成的优化任务,目标是让生成的视频转场更自然、文案更贴合目的地。今天要试一个新开源模型的效果。mentor听完说:“先跑个AB实验,数据说话。” 11:00|写代码+调模型,沉浸式...
携程成长空间 146人发布
点赞
评论
收藏
分享
05-02 14:57
门头沟学院 C++
暑期实习-蚂蚁
有大佬知道蚂蚁智安安全技术有限公司的吗?想问一下这个是内包吗,属于蚂蚁的正编吗
我的求职进度条
点赞
评论
收藏
分享
不愿透露姓名的神秘牛友
04-21 17:34
我真蠢,上班三天才知道mt让看文档啥意思
第一次实习的时候啥也不懂mentor第一天跟我说的。我说好。我以为只是第一天这样。第二天——"你先看看文档。"第三天——"你先看看文档。"第五天我鼓起勇气问:"那我后面大概做什么方向?"他说:"不急,先熟悉。"我点开过的文档数了数,三十多篇。每一篇我都有认真看实在无聊,我打开同学群看看大家都干啥呢。有人说他入职第一天就改了bug。有人说他mentor每天带他review代码。有人说他们组上周聚餐了。我每天的成就是:又看了五篇文档。上了一周班后,晚上我收工位走出公司,那一刻我突然明白"你先看看文档"是什么意思。不是让我熟悉。是他也不知道让我干嘛。我真的谢
文聚星:
说明你这是大厂,小厂才会来了直接上手写
实习时最怕听到的一句话
点赞
评论
收藏
分享
04-30 14:25
已编辑
门头沟学院 后端工程师
28届对简历再次简单优化了下
唉,继续投吧 有无一起找实习的同志抱个团
点赞
评论
收藏
分享
昨天 14:09
电子科技大学 C++
美团offer
timeline笔试 4.18一面 4.23二面 4.28offer 5.7
我的求职进度条
点赞
评论
收藏
分享
评论
点赞成功,聊一聊 >
1
收藏
分享
评论
提到的真题
返回内容
全站热榜
更多
1
...
毕业了,有些话只能藏在心里了
1.9W
2
...
毕业啦!我们要一起去广州打拼啦!
1.9W
3
...
2026春招到底卷成什么样了?填问卷说出真相,最高领200元现金红包
1.5W
4
...
字节 中国交易与广告 后端一面
1.2W
5
...
211本,130投0面,agent应用开发,简历求助!
7932
6
...
从阿里被裁到快手升P6,我花了四年
7648
7
...
华为暑期实习
7157
8
...
从腾讯到阿里感,谢一路走来的自己
6548
9
...
别人:阿里 字节 腾讯
6520
10
...
在携程的一天
6384
创作者周榜
更多
正在热议
更多
#
这个offer值得去吗?
#
30976次浏览
224人参与
#
校招薪资来揭秘
#
960327次浏览
4061人参与
#
联宝杯大学生创新大赛,你的技术值得产业级答案
#
50644次浏览
781人参与
#
如果春招能重来,我会___
#
29047次浏览
286人参与
#
24秋招避雷总结
#
1019791次浏览
7098人参与
#
你会因为行情,降低找工作标准吗?
#
44646次浏览
324人参与
#
在爱玛,骑向未来
#
20113次浏览
394人参与
#
机械人还在等华为开奖吗?
#
339145次浏览
1652人参与
#
米哈游求职进展汇总
#
688516次浏览
3348人参与
#
华为池子有多大
#
177958次浏览
931人参与
#
26届春招投递记录
#
8590次浏览
71人参与
#
通信/硬件求职避坑tips
#
171963次浏览
1170人参与
#
25届网易互娱暑实进度
#
109055次浏览
802人参与
#
记录我的毕业季
#
4422次浏览
116人参与
#
机械人,你的秋招第一份简历被谁挂了
#
268708次浏览
2450人参与
#
远程面试的尴尬瞬间
#
363758次浏览
2062人参与
#
大学最后一个寒假,我想……
#
103264次浏览
846人参与
#
机械求职避坑tips
#
103639次浏览
589人参与
#
你认为小厂实习有用吗?
#
144999次浏览
762人参与
#
网易求职进展汇总
#
213088次浏览
1523人参与
#
美团秋招笔试
#
216268次浏览
1191人参与
#
刚入职就____,这样正常吗?
#
148957次浏览
709人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务