目录
- Tomcat类加载器的层次结构
- WebAppClassLoader
- SharedClassLoader
- CatalinaClassLoader
- CommonClassLoader
- Spring的加载问题
- 线程上下文加载器
- 总结
Tomcat负责加载我们的Servlet类、加载Servlet所依赖的JAR包 。Tomcat本身也是个Java程序,因此它需要加载自己的类和依赖的JAR包 。
若在Tomcat运行两个Web应用程序,它们有功能不同的同名Servlet,Tomcat需同时加载和管理这两个同名的Servlet类,保证它们不会冲突 。所以Web应用之间的类需要隔离
若两个Web应用都依赖同一三方jar,比如Spring,则Spring jar被加载到内存后,Tomcat要保证这两个Web应用能共享之,即Spring jar只被加载一次,否则随着三方jar增多,JVM的内存会占用过大 。
所以,和 JVM 一样,需要隔离Tomcat本身的类和Web应用的类 。
Tomcat类加载器的层次结构Tomcat的类加载器层次结构
前三个是加载器实例名,不是类名 。
WebAppClassLoader若使用JVM默认的AppClassLoader加载Web应用,AppClassLoader只能加载一个Servlet类,在加载第二个同名Servlet类时,AppClassLoader会返回第一个Servlet类的Class实例 。
因为在AppClassLoader眼里,同名Servlet类只能被加载一次 。
于是,Tomcat自定义了一个类加载器WebAppClassLoader,并为每个Web应用创建一个WebAppClassLoader实例 。
每个Web应用自己的Java类和依赖的JAR包,分别放在
WEB-INF/classes
和WEB-INF/lib
目录下,都是WebAppClassLoader加载的 。Context容器组件对应一个Web应用,因此,每个Context容器创建和维护一个WebAppClassLoader加载器实例 。
不同加载器实例加载的类被认为是不同的类,即使类名相同 。这就相当于在JVM内部创建相互隔离的Java类空间,每个Web应用都有自己的类空间,Web应用之间通过各自的类加载器互相隔离 。
SharedClassLoader两个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实例之间相互隔离 。
推荐阅读
- 使用jconsole监听Tomcat远程服务的配置方法
- 云转型谈何容易?打破转型阵痛,汇量科技加码云原生
- Tomcat的Server Options选项详解大全
- nginx和tomcat区别
- 汽车刷ecu有哪些影响
- 梦见跟人打架头被打破了
- 原神风墙怎么打破
- 奇怪的冰怎么打破
- 原神雪山蓝色远古石头怎么打破
- 张仪怎么打破六国合纵的