Tomcat类加载器
字数 1907 2025-08-10 10:14:26
Tomcat类加载器机制详解
1. Tomcat类加载器的设计背景
Tomcat作为一个Web容器,需要支持多个应用程序的部署,这些应用程序可能依赖不同版本的第三方库。因此,Tomcat需要实现以下目标:
- 隔离性:不同应用依赖的不同版本类库需要隔离
- 共享性:某些基础类库需要被所有应用共享
- 灵活性:支持热部署等特性
2. Tomcat类加载器层次结构
Tomcat实现了多层次的类加载器,按照从父到子的顺序依次为:
- Bootstrap类加载器:JVM自带的类加载器
- System类加载器:JVM自带的类加载器
- Common类加载器
- Catalina类加载器
- Shared类加载器
- Webapp类加载器
- JasperLoader
2.1 Common类加载器
- 作用:Tomcat最基本的类加载器
- 加载路径:默认加载
$CATALINA_HOME/lib下的jar包 - 初始化过程:
- 在Bootstrap中初始化
- 调用
createClassLoader创建 - 作为catalinaLoader和sharedLoader的父加载器
- 通过
CatalinaProperties.getProperty获取要加载的路径
2.2 Catalina类加载器
- 特点:
- Tomcat容器私有的类加载器
- 加载路径中的class对Webapp不可见
- 初始化过程:
- 在Bootstrap中初始化
- 以commonLoader作为父加载器
- 默认加载路径为空,直接使用父加载器
- 用于加载
org.apache.catalina.startup.Catalina - 通过反射将
ParentClassLoader改为sharedLoader
2.3 Shared类加载器
- 特点:
- 各个Webapp共享的类加载器
- 加载路径中的class对所有Webapp可见
- 对Tomcat容器不可见
- 初始化过程:
- 在Bootstrap中初始化
- 以commonLoader作为父加载器
- 默认加载路径为空,直接使用父加载器
- 通过反射将
Catalina.parentClassLoader设置为sharedLoader
2.4 Webapp类加载器
- 特点:
- 各个Webapp私有的类加载器
- 加载
WEB-INF/libs和WEB-INF/classes目录下的内容 - 可以使用SharedClassLoader加载的类
- 不同WebAppClassLoader实例之间相互隔离
- 初始化:在
StandardContext.startInternal中初始化
2.5 JasperLoader
- 特点:
- 专门用于加载JSP文件编译后的Class
- 加载范围仅限于单个JSP文件编译出的Class
- 设计目的是为了支持热部署
- 工作机制:
- 当检测到JSP文件被修改时,会替换当前JasperLoader实例
- 创建新的Jsp类加载器实现热部署
3. Tomcat类加载机制特点
3.1 违反双亲委派模型
Tomcat的类加载机制违反了标准的双亲委派原则,具体实现如下:
- 首先调用
findLoadedClass0从缓存中查找已加载的类 - 如果开启了双亲委派机制,先委派父加载器加载
- 使用WebApp类加载器扫描
WEB-INF/libs和WEB-INF/classes目录 - 如果没有开启双亲委派,使用commonLoader加载
- 所有加载器都加载不到时,抛出
ClassNotFoundException
3.2 数组类加载的特殊性
- 可以加载:共享库中的对象数组(如
[Ljava.lang.StackTraceElement;) - 不能加载:自定义类和第三方类的对象数组(如
[Lorg.apache.commons.collections.Transformer;)
4. 类加载流程源码分析
关键方法:WebappClassLoaderBase#loadClass(java.lang.String, boolean)
- 检查缓存中是否已加载
- 检查是否启用双亲委派
- 尝试使用WebApp类加载器加载
- 尝试使用父类加载器加载
- 最终抛出异常
5. 总结
Tomcat的类加载机制设计特点:
- 隔离与共享并存:既实现了应用间的隔离,又支持公共库的共享
- 热部署支持:通过JasperLoader实现JSP的热部署
- 灵活的双亲委派:可以根据需要选择是否遵循双亲委派模型
- 安全性:虽然违反双亲委派,但不会导致核心API被篡改
这种设计使得Tomcat能够:
- 支持多个应用部署
- 解决依赖冲突问题
- 提供热部署能力
- 保持系统稳定性