Tomcat如何打破双亲委托机制?

本文详细解读了Java虚拟机中的类加载器工作原理,特别是双亲委托机制,以及Tomcat如何通过自定义WebAppClassLoader打破这一机制,优先加载Web应用内的类。作者还分享了类加载器的实现方式和类加载流程。
摘要由CSDN通过智能技术生成

protected final Class<?> defineClass(byte[] b, int off, int len){

}

}

JVM的类加载器是分层的父子关系,每个类加载器都持有一个parent字段指向父加载器。

  • defineClass 工具方法:调用native方法把Java类的字节码解析成一个Class对象

  • findClass 就是找到 .class 文件,可能来自文件系统或网络,找到后把 .class 文件读到内存得到字节码数组,然后调用defineClass方法得到Class对象

loadClass 首先检查这个类是不是已经被加载过了,如果加载过了直接返回,否则交给父加载器去加载。

这是个递归调用,即子加载器持有父加载器引用,当一个类加载器需加载一个Java类时,会先委托父加载器去加载,然后父加载器在自己加载路径中搜索Java类,当父加载器在自己的加载范围内找不到时,才会交还给子加载器加载,这就是双亲委托机制。

JDK的类加载器工作原理是一样的,区别只是加载路径不同,即findClass查找的路径不同。

双亲委托机制是为保证一个Java类在JVM的唯一性。假如你手滑写个与JRE核心类同名类,比如Object,双亲委托机制能保证加载的是JRE里的那个Object类,而不是你写的Object。

因为AppClassLoader在加载你的Object类时,会委托给ExtClassLoader去加载,而ExtClassLoader又会委托给BootstrapClassLoader,BootstrapClassLoader发现自己已经加载过了Object类,会直接返回,不会去加载你的Object类。

类加载器的父子关系不是通过继承来实现的,比如AppClassLoader并非ExtClassLoader的子类,只是AppClassLoader的parent指向ExtClassLoader对象。

所以若自定义类加载器,不是去继承AppClassLoader,而是继承ClassLoader抽象类,再重写findClass和loadClass即可。

Tomcat就是通过自定义类加载器实现自己的类加载。

若你要打破双亲委托,也就只需重写loadClass,因为loadClass的默认实现就是双亲委托机制。

Tomcat的类加载器

==========================================================================

Tomcat的自定义类加载器WebAppClassLoader打破了双亲委托机制:

首先自己尝试去加载某个类,如果找不到再委托给父类加载器,目的是优先加载Web应用自己定义的类。

只需重写ClassLoader的两个方法:

findClass


public Class<?> findClass(String name) throws ClassNotFoundException {

Class<?> clazz = null;

try {

//1. 先在Web应用目录下查找类

clazz = findClassInternal(name);

} catch (RuntimeException e) {

throw e;

}

if (clazz == null) {

try {

//2. 如果在本地目录没有找到,交给父加载器去查找

clazz = super.findClass(name);

} catch (RuntimeException e) {

throw e;

}

//3. 如果父类也没找到,抛出ClassNotFoundException

if (clazz == null) {

throw new ClassNotFoundException(name);

}

return clazz;

}

工作流程

  • 先在Web应用本地目录下查找要加载的类

  • 若未找到,交给父加载器查找,即AppClassLoader

  • 若父加载器也没找到这个类,抛ClassNotFound

loadClass


public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {

synchronized (getClassLoadingLock(name)) {

Class<?> clazz = null;

//1. 先在本地cache查找该类是否已经加载过

clazz = findLoadedClass0(name);

if (clazz != null) {

if (resolve)

resolveClass(clazz);

return clazz;

}

//2. 从系统类加载器的cache中查找是否加载过

clazz = findLoadedClass(name);

if (clazz != null) {

if (resolve)

resolveClass(clazz);

return clazz;

}

// 3. 尝试用ExtClassLoader类加载器类加载,为什么?

ClassLoader javaseLoader = getJavaseClassLoader();

try {

clazz = javaseLoader.loadClass(name);

if (clazz != null) {

if (resolve)

resolveClass(clazz);

return clazz;

}

} catch (ClassNotFoundException e) {

// Ignore

}

// 4. 尝试在本地目录搜索class并加载

try {

clazz = findClass(name);

if (clazz != null) {

if (resolve)

resolveClass(clazz);

return clazz;

}

} catch (ClassNotFoundException e) {

// Ignore

}

// 5. 尝试用系统类加载器(也就是AppClassLoader)来加载

try {

clazz = Class.forName(name, false, parent);

if (clazz != null) {

if (resolve)

resolveClass(clazz);

return clazz;

}

} catch (ClassNotFoundException e) {

// Ignore

}

}

//6. 上述过程都加载失败,抛出异常

throw new ClassNotFoundException(name);

}

工作流程

  • 先在本地Cache查找该类是否已加载过

即Tomcat的类加载器是否已经加载过这个类。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

感受:

其实我投简历的时候,都不太敢投递阿里。因为在阿里一面前已经过了字节的三次面试,投阿里的简历一直没被捞,所以以为简历就挂了。

特别感谢一面的面试官捞了我,给了我机会,同时也认可我的努力和态度。对比我的面经和其他大佬的面经,自己真的是运气好。别人8成实力,我可能8成运气。所以对我而言,我要继续加倍努力,弥补自己技术上的不足,以及与科班大佬们基础上的差距。希望自己能继续保持学习的热情,继续努力走下去。

也祝愿各位同学,都能找到自己心动的offer。

分享我在这次面试前所做的准备(刷题复习资料以及一些大佬们的学习笔记和学习路线),都已经整理成了电子文档

拿到字节跳动offer后,简历被阿里捞了起来,二面迎来了P9"盘问"

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
气。所以对我而言,我要继续加倍努力,弥补自己技术上的不足,以及与科班大佬们基础上的差距。希望自己能继续保持学习的热情,继续努力走下去。

也祝愿各位同学,都能找到自己心动的offer。

分享我在这次面试前所做的准备(刷题复习资料以及一些大佬们的学习笔记和学习路线),都已经整理成了电子文档

[外链图片转存中…(img-RpTC0OXz-1713434098122)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 8
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值