Tomcat如何打破双亲委派机制实现隔离Web应用的?

双亲委派机制的各子加载器都能通过父加载器去加载类,于是考虑把需共享的类放到父加载器的加载路径。

应用程序即是通过该方式共享JRE核心类。

Tomcat搞了个类加载器SharedClassLoader,作为WebAppClassLoader的父加载器,以加载Web应用之间共享的类。

若WebAppClassLoader未加载到某类,就委托父加载器SharedClassLoader去加载该类,SharedClassLoader会在指定目录下加载共享类,之后返回给WebAppClassLoader,即可解决共享问题。

CatalinaClassLoader


如何隔离Tomcat本身的类和Web应用的类?

兄弟关系:两个类加载器是平行的,它们可能拥有同一父加载器,但两个兄弟类加载器加载的类是隔离的。

于是,Tomcat搞了CatalinaClassLoader,专门加载Tomcat自身的类。

问题是,当Tomcat和各Web应用之间需要共享一些类时该怎么办?

CommonClassLoader


共享依旧靠父子关系。

再增加个CommonClassLoader,作为CatalinaClassLoader和SharedClassLoader的父加载器。

CommonClassLoader能加载的类都可被CatalinaClassLoader、SharedClassLoader 使用,而CatalinaClassLoader和SharedClassLoader能加载的类则与对方相互隔离。WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader实例之间相互隔离。

Spring的加载问题

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

JVM默认情况下,若一个类由类加载器A加载,则该类的依赖类也由相同的类加载器加载。

比如Spring作为一个Bean工厂,它需要创建业务类的实例,并且在创建业务类实例之前需要加载这些类。Spring是通过调用Class.forName来加载业务类的,我们来看一下forName的源码:

public static Class<?> forName(String className) {

Class<?> caller = Reflection.getCallerClass();

return forName0(className, true, ClassLoader.getClassLoader(caller), caller);

}

会使用调用者,即Spring的加载器去加载业务类。

Web应用之间共享的jar可交给SharedClassLoader加载,以避免重复加载。Spring作为共享的三方jar,本身由SharedClassLoader加载,Spring又要去加载业务类,按照前面那条规则,加载Spring的类加载器也会用来加载业务类,但是业务类在Web应用目录下,不在SharedClassLoader的加载路径下,这该怎么办呢?

线程上下文加载器


于是有了线程上下文加载器,一种类加载器传递机制。因为该类加载器保存在线程私有数据里,只要是同一个线程,一旦设置了线程上下文加载器,在线程后续执行过程中就能把这个类加载器取出来用。因此Tomcat为每个Web应用创建一个WebAppClassLoader类加载器,并在启动Web应用的线程里设置线程上下文加载器,这样Spring在启动时就将线程上下文加载器取出来,用来加载Bean。Spring取线程上下文加载的代码如下:

cl = Thread.currentThread().getContextClassLoader();

在StandardContext的启动方法,会将当前线程的上下文加载器设置为WebAppClassLoader。

启动方法结束时,会恢复线程的上下文加载器:

Thread.currentThread().setContextClassLoader(originalClassLoader);

这是为什么呢?

线程上下文加载器其实是线程的一个私有数据,跟线程绑定,这个线程完成启动Context组件后,会被回收到线程池,之后被用来做其他事情,为了不影响其他事情,需恢复之前的线程上下文加载器。

优先加载web应用的类,当加载完了再改回原来的。

线程上下文的加载器就是指定子类加载器来加载具体的某个桥接类,比如JDBC的Driver的加载。

总结

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

Tomcat的Context组件为每个Web应用创建一个WebAppClassLoader类加载器,由于不同类加载器实例加载的类是互相隔离的,因此达到了隔离Web应用的目的,同时通过CommonClassLoader等父加载器来共享第三方JAR包。而共享的第三方JAR包怎么加载特定Web应用的类呢?可以通过设置线程上下文加载器来解决。

多个应用共享的Java类文件和JAR包,分别放在Web容器指定的共享目录:

  • CommonClassLoader

对应 <Tomcat>/common/*

  • CatalinaClassLoader

最后

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

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

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

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

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

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值