Tomcat类加载器
字数 1907 2025-08-10 10:14:26

Tomcat类加载器机制详解

1. Tomcat类加载器的设计背景

Tomcat作为一个Web容器,需要支持多个应用程序的部署,这些应用程序可能依赖不同版本的第三方库。因此,Tomcat需要实现以下目标:

  • 隔离性:不同应用依赖的不同版本类库需要隔离
  • 共享性:某些基础类库需要被所有应用共享
  • 灵活性:支持热部署等特性

2. Tomcat类加载器层次结构

Tomcat实现了多层次的类加载器,按照从父到子的顺序依次为:

  1. Bootstrap类加载器:JVM自带的类加载器
  2. System类加载器:JVM自带的类加载器
  3. Common类加载器
  4. Catalina类加载器
  5. Shared类加载器
  6. Webapp类加载器
  7. 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/libsWEB-INF/classes目录下的内容
    • 可以使用SharedClassLoader加载的类
    • 不同WebAppClassLoader实例之间相互隔离
  • 初始化:在StandardContext.startInternal中初始化

2.5 JasperLoader

  • 特点
    • 专门用于加载JSP文件编译后的Class
    • 加载范围仅限于单个JSP文件编译出的Class
    • 设计目的是为了支持热部署
  • 工作机制
    • 当检测到JSP文件被修改时,会替换当前JasperLoader实例
    • 创建新的Jsp类加载器实现热部署

3. Tomcat类加载机制特点

3.1 违反双亲委派模型

Tomcat的类加载机制违反了标准的双亲委派原则,具体实现如下:

  1. 首先调用findLoadedClass0从缓存中查找已加载的类
  2. 如果开启了双亲委派机制,先委派父加载器加载
  3. 使用WebApp类加载器扫描WEB-INF/libsWEB-INF/classes目录
  4. 如果没有开启双亲委派,使用commonLoader加载
  5. 所有加载器都加载不到时,抛出ClassNotFoundException

3.2 数组类加载的特殊性

  • 可以加载:共享库中的对象数组(如[Ljava.lang.StackTraceElement;
  • 不能加载:自定义类和第三方类的对象数组(如[Lorg.apache.commons.collections.Transformer;

4. 类加载流程源码分析

关键方法:WebappClassLoaderBase#loadClass(java.lang.String, boolean)

  1. 检查缓存中是否已加载
  2. 检查是否启用双亲委派
  3. 尝试使用WebApp类加载器加载
  4. 尝试使用父类加载器加载
  5. 最终抛出异常

5. 总结

Tomcat的类加载机制设计特点:

  1. 隔离与共享并存:既实现了应用间的隔离,又支持公共库的共享
  2. 热部署支持:通过JasperLoader实现JSP的热部署
  3. 灵活的双亲委派:可以根据需要选择是否遵循双亲委派模型
  4. 安全性:虽然违反双亲委派,但不会导致核心API被篡改

这种设计使得Tomcat能够:

  • 支持多个应用部署
  • 解决依赖冲突问题
  • 提供热部署能力
  • 保持系统稳定性
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能够: 支持多个应用部署 解决依赖冲突问题 提供热部署能力 保持系统稳定性