深入拆解 Tomcat & Jetty
李号双
eBay 技术主管
38890 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 45 讲
开篇词 (1讲)
深入拆解 Tomcat & Jetty
15
15
1.0x
00:00/00:00
登录|注册

24 | Context容器(上):Tomcat如何打破双亲委托机制?

loadClass方法
findClass方法
AppClassLoader
ExtClassLoader
BootstrapClassLoader
defineClass方法
findClass方法
loadClass方法
重写findClass和loadClass方法
重写loadClass方法
继承ClassLoader抽象类
WebAppClassLoader
双亲委托机制
ClassLoader抽象类
分层次的类加载器
课后思考
打破双亲委托机制
Tomcat的类加载器
JVM的类加载器
总结

该思维导图由 AI 生成,仅供参考

相信我们平时在工作中都遇到过 ClassNotFound 异常,这个异常表示 JVM 在尝试加载某个类的时候失败了。想要解决这个问题,首先你需要知道什么是类加载,JVM 是如何加载类的,以及为什么会出现 ClassNotFound 异常?弄懂上面这些问题之后,我们接着要思考 Tomcat 作为 Web 容器,它是如何加载和管理 Web 应用下的 Servlet 呢?
Tomcat 正是通过 Context 组件来加载管理 Web 应用的,所以今天我会详细分析 Tomcat 的类加载机制。但在这之前,我们有必要预习一下 JVM 的类加载机制,我会先回答一下一开始抛出来的问题,接着再谈谈 Tomcat 的类加载器如何打破 Java 的双亲委托机制。

JVM 的类加载器

Java 的类加载,就是把字节码格式“.class”文件加载到 JVM 的方法区,并在 JVM 的堆区建立一个java.lang.Class对象的实例,用来封装 Java 类相关的数据和方法。那 Class 对象又是什么呢?你可以把它理解成业务类的模板,JVM 根据这个模板来创建具体业务类对象实例。
JVM 并不是在启动时就把所有的“.class”文件都加载一遍,而是程序在运行过程中用到了这个类才去加载。JVM 类加载是由类加载器来完成的,JDK 提供一个抽象类 ClassLoader,这个抽象类中定义了三个关键方法,理解清楚它们的作用和关系非常重要。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Tomcat的类加载器是如何打破双亲委托机制的?本文深入解析了JVM的类加载机制和Tomcat的自定义类加载器WebAppClassLoader的实现原理。首先介绍了JVM的类加载机制,包括ClassLoader的层次结构和关键方法,以及JDK中默认的类加载器。重点解释了双亲委托机制的作用,即保证JVM中的类是唯一的。文章指出,要打破双亲委托机制,需要重写loadClass方法,因为loadClass的默认实现就是双亲委托机制。然后详细分析了Tomcat的类加载器的findClass和loadClass方法的实现,展示了Tomcat是如何通过自定义类加载器来实现自己的类加载逻辑,优先加载Web应用自己定义的类。通过对Tomcat类加载器的源码剖析,读者可以深入了解Java类加载机制的实现原理,以及如何打破双亲委托机制。文章内容丰富,对于想深入了解JVM类加载机制和Tomcat类加载器实现的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入拆解 Tomcat & Jetty 》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(58)

  • 最新
  • 精选
  • 罗 乾 林
    我想打破双亲委托机制,能保证不同版本的类共存,就像一个tomcat下多个工程,使用了不同版本的spring,各加载各的互不影响。如果不打破双亲委托机制,都交由AppClassLoader去加载,那么相同包名相同类名的类就被判定已经加载过了,达不到加载不同版本的功能。由于自定义了类加载器,即使包名与类名相同,但类加载器不同依然被判断为不同的类

    作者回复: 对的,下一篇就说隔离

    2019-07-06
    43
  • nightmare
    tomcat的类加载机制老师剖析的很透彻,先扩展类加载器加载,这样避免自己覆盖JRE中的类然后再自定义的加载器加载,最后应用加载器加载,有一个疑问,就是比如我一个tomcat部署了多个web应用,如果都有spring的jar包,由于自定义的类加载器先加载spring的jar包,这样spring的jar在每一个context应用岂不是都要加载一次?如果应用加载器先加载,是不是就可以只加载一次spring的jar,然后自定义的加载器只加载不共用的class?

    作者回复: 你说的很对,Spring的类应该是由sharedclassloader来加载,所以不应该把Spring的包放到Web应用的路径下,应该放到Tomcat指定的共享目录下

    2019-07-04
    31
  • Monday
    1、原文【tomcat 的自定义类加载器 WebAppClassLoader 打破了双亲委托机制,它首先自己尝试去加载某个类,如果找不到再代理给父类加载器,其目的是优先加载 Web 应用自己定义的类。具体实现就是重写 ClassLoader 的两个方法:findClass 和 loadClass。】 问题:就不怕tomcat类加载器覆盖ExtClassloader加载的类? 2、原文【从上面的过程我们可以看到,Tomcat 的类加载器打破了双亲委托机制,没有一上来就直接委托给父加载器,而是先在本地目录下加载,为了避免本地目录下的类覆盖 JRE 的核心类,先尝试用 JVM 扩展类加载器 ExtClassLoader 去加载。那为什么不先用系统类加载器 AppClassLoader 去加载?很显然,如果是这样的话,那就变成双亲委托机制了,这就是 Tomcat 类加载器的巧妙之处。】 问题:后面的回答,感觉像是为了打破而打破似的。 3、听/看本节多次,最后还是没体悟到Tomcat打破双亲委托模式的好处。。。

    作者回复: 假如web应用目录下有个Spring2.0版本的库,系统class类路径下有个Spring 1.0版本的库,打破双亲委托的好处是web应用会加载web应用路径下那个Spring。

    2019-07-08
    5
    22
  • 吖蒲
    老师,我看源码了还是有点不懂,第三步骤tomcat的类加载器先用extclassloader加载类,ext让父加载器bootstrap去加载,防止优先加载应用中同名的类,那我用appclassloader,最终也能达到bootstrap加载器去加载类的效果,那为什么不直接调用appclassloader加载??

    作者回复: 好问题,appclassloader会加载PATH目录下的类,这样就达不到优先加载web应用目录下类的目的了

    2019-08-08
    4
    16
  • nightmare
    我明白了,比如可以把多个项目共享的jar包放到${CATALINA_HOME}/shared目录下,让sharedclassloader来加载,并且是所有context的web应用共享的,而都有的放在web路径下,先让扩展类加载器加载,避免覆盖jre中的类,再让自定义的web加载器来加载独有的类,最后加载让应用加载器加载扩展类加载器和自定义加载器加载不到的类,谢谢李老师

    作者回复: 👍

    2019-07-04
    2
    15
  • 强哥
    每篇文章最后的总结,若能概括出这么做的意图及优点,这样对读者来说收益更大。

    作者回复: Servlet规范建议,全路径类名与系统类同名的话,优先加载web应用自己定义的类。

    2019-07-04
    13
  • Li Shunduo
    在其他地方看到过可以通过配置<Loader delegate="true"/>让tomcat遵循双亲委派,老师在答疑篇可以展开讲讲吗?

    作者回复: 是的,如果你不想Tomcat打破双亲委托,可以配这个参数

    2019-07-10
    11
  • Mr.差不多
    双亲委派规则是 当父加载器找不到此文件时才交给子加载器去加载。那么我觉得Tomcat重写loadClass方法其实也是这个逻辑。假设现在有一个类是需要在WebAppClassLoader加载的,那么它会先查询是否在AppClassLoader加载过,如果没有那么查看是否在ExtClassLoader加载过,那么这一系列步骤不就是为了保证没有在父加载器找不到此文件吗?这不还是双亲委派的模型吗?麻烦老师给解答下

    作者回复: WebAppClassLoader不会首先委托给AppClassLoader去加载,而是ExtClassLoader。这是根本区别

    2019-07-05
    3
    11
  • Liam
    老师能讲下什么是上下文加载器吗,什么情况下会用到它?这个和双亲委派有关吗

    作者回复: 线程上下文加载器其实是线程私有数据,跟线程绑定的属性

    2019-07-04
    3
    9
  • 飞翔
    老师 您说 java 的类加载器,就是把字节码格式.class 文件加载到JVM的方法区,并在JVM的堆区建立一个java.lang.Class 对象实例 那loadclass方法负责把字节码格式.class 文件加载到JVM的方法区 和defineclass负责在JVM的堆区建立一个java.lang.Class 对象实例 这样理解对嘛

    作者回复: 对的

    2019-07-23
    8
收起评论
显示
设置
留言
58
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部