当前位置: 首页 > news >正文

Tomcat类加载器原理简单介绍

1.1 Java类加载器基础

在深入了解 Tomcat的类加载器机制 之前,我们需要先回顾 Java类加载器(ClassLoader) 的基本原理。

类加载器的作用
在JVM中,类的字节码文件(.class)并不是一次性全部加载进内存的,而是由 类加载器 在需要时动态加载。类加载器的职责就是:

  1. 根据类的全限定名找到对应的字节码文件;

  2. 将字节码转换为 Class 对象;

  3. 缓存加载过的类,避免重复加载。

JVM内置的类加载器层次

  • Bootstrap ClassLoader:最顶层,由C++实现,加载 rt.jar 等核心类库(java.lang.*java.util.*)。

  • Extension ClassLoader:加载 JAVA_HOME/lib/ext 目录下的扩展包。

  • System ClassLoader(AppClassLoader):加载 classpath 下的用户类。

这三者之间遵循 双亲委派模型

  • 一个类加载请求会 先交给父加载器 处理;

  • 父加载器如果无法加载,才由当前加载器尝试。

👉 类比:就像你去快递站取包裹,前台会先让上级仓库查一遍,如果没有,才在自己仓库里找。


1.2 Tomcat类加载器层级结构

Tomcat是一个Web容器,它不仅需要加载自身的类库,还需要为每个Web应用加载 隔离的类空间。因此,Tomcat在JVM默认类加载器基础上,构建了自己的层次结构。

Tomcat主要的类加载器有:

  1. Common ClassLoader

    • 加载 $CATALINA_HOME/lib 下的类库。

    • Tomcat自身和所有Web应用共享。

  2. Catalina ClassLoader

    • 加载 Tomcat 核心模块(如 org.apache.catalina.*)。

  3. Shared ClassLoader

    • 用于多个Web应用共享的类库(默认与 Common 合并)。

  4. WebappClassLoader

    • 每个Web应用都有独立的一个实例,加载 WEB-INF/classesWEB-INF/lib

    • 保证Web应用之间相互隔离。

层级关系示意图

Bootstrap ClassLoader↓System ClassLoader↓Common ClassLoader↙           ↘
CatalinaCL     SharedCL↓WebappClassLoader (per app)

特点

  • 保证Tomcat内核和Web应用解耦;

  • 不同Web应用之间互不影响(避免Jar包冲突);

  • 通过 Common → Shared → Webapp 的逐级传递,实现共享与隔离并存。


1.3 双亲委派模型与Tomcat的定制化实现

JVM默认机制

Java类加载器默认采用 严格的双亲委派模型,优先保证 核心类库的安全性与一致性。例如,应用自己写的 java.lang.String 类永远不会被加载,因为会优先从 Bootstrap 找到官方的版本。

Tomcat的需求

但是在Web容器中,情况变得复杂:

  • 每个Web应用可能依赖 不同版本的同一个库(如 log4j)。

  • Web应用可能需要 覆盖Tomcat内置类库(如JSP编译器依赖的EL实现)。

👉 如果完全遵循双亲委派,就会导致:

  • Web应用无法加载自己的依赖;

  • 不同应用之间库冲突。

Tomcat的解决方案

Tomcat在 WebappClassLoaderBase打破了部分双亲委派规则

  • 优先加载Web应用自身的类

  • 如果本地找不到,才委派给父加载器。

核心源码(Tomcat 10.1.7):

@Override
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {synchronized (name.intern()) {// 1. 已加载过?Class<?> clazz = findLoadedClass0(name);if (clazz != null) return clazz;// 2. 先尝试在当前Webapp中查找try {clazz = findClass(name);if (clazz != null) return clazz;} catch (ClassNotFoundException ignored) {}// 3. 找不到再委派父加载器try {clazz = getParent().loadClass(name);if (clazz != null) return clazz;} catch (ClassNotFoundException ignored) {}throw new ClassNotFoundException(name);}
}

👉 可以看到,Tomcat的逻辑是:
Web应用优先 → 父加载器兜底,从而在保证隔离性的同时,也提供灵活性。


1.4 热部署与热加载机制

Web开发中,我们常常会修改JSP文件或更新依赖Jar,Tomcat支持 热加载(Hot Reloading)

  • JSP更新:Tomcat通过 JspServlet 自动检测文件变更并重新编译。

  • Web应用重新加载:Tomcat会销毁旧的 WebappClassLoader,并创建一个新的实例。

👉 原理:

  • 当检测到 WEB-INF/classesWEB-INF/lib 发生变化时,Tomcat调用 WebappLoaderstop() 方法。

  • 销毁旧的类加载器,释放相关资源(类缓存、Jar文件句柄)。

  • 创建新的 WebappClassLoader 实例,重新加载类。

注意:由于类卸载受JVM GC机制影响,如果存在静态引用、线程未释放等情况,会导致 类加载器泄漏ClassLoader Leak)。这也是Tomcat运维常见问题之一。


1.5 源码解析与实战案例

让我们结合源码走一遍流程(Tomcat 10.1.7):

类加载器初始化

Tomcat启动时,会初始化 Catalina.createClassLoader()

protected ClassLoader createClassLoader(String name, ClassLoader parent) {try {return ClassLoaderFactory.createClassLoader(new String[] { "lib" },   // 加载路径parent);} catch (Throwable t) {throw new RuntimeException("Cannot create class loader", t);}
}

Web应用加载

每个 Context(即Web应用)对应一个 WebappLoader,其内部持有 WebappClassLoaderBase

WebappLoader loader = new WebappLoader();
context.setLoader(loader);

启动时,Tomcat会为该应用创建一个新的 WebappClassLoader,负责加载 WEB-INF/libWEB-INF/classes


小结

这一章我们从 Java类加载器基础 出发,逐层分析了 Tomcat的类加载器体系,并结合源码展示了其如何在 双亲委派模型 上进行定制化改造,从而支持Web应用的隔离、共享与热加载。

核心要点:

  1. Tomcat类加载器结构分层:Common → Shared → Webapp

  2. Tomcat打破了双亲委派,优先加载应用内类。

  3. 热部署依赖于销毁并重建 WebappClassLoader


思考题

  1. 为什么JVM设计时采用双亲委派模型?

  2. 如果Tomcat完全遵循双亲委派,会导致哪些问题?

  3. 类加载器泄漏通常是怎么产生的?在Tomcat运维中该如何避免?

http://www.lryc.cn/news/622973.html

相关文章:

  • AI热点周报(8.10~8.16):AI界“冰火两重天“,GPT-5陷入热议,DeepSeek R2模型训练受阻?
  • 服务器可以ping通,但部署的网站打不开
  • uniapp:微信小程序使用Canvas 和Canvas 2D绘制图形
  • nginx下载地址:aarch64
  • Scala面试题及详细答案100道(11-20)-- 函数式编程基础
  • 狗品种识别数据集:1k+图像,6个类别,yolo标注完整
  • linux docker neo4j 导出 (windows 导入)
  • duiLib 实现鼠标拖动状态栏时,窗口跟着拖动
  • 模型量化(Model Quantization)
  • 解决 Windows 下运行 MCP 脚本弹出 WSH 错误窗口的问题 | Windows Script Host
  • 【数据分析】比较SparCC、Pearson和Spearman相关性估计方法在合成组学数据上的表现
  • Footej Camera 2:专业级摄影体验,尽在掌中
  • 《代码重生:杨蓉与62.webp》
  • 2024-2025华为ICT大赛中国区 实践赛昇腾AI赛道(高职组)全国总决赛 理论部分真题+解析
  • 基本电子元件:金属氧化膜电阻器
  • 测试工程师的AI转型指南:从工具使用到测试策略重构
  • Vue组件基础解析
  • 机器学习--决策树
  • [Linux] RAID存储技术
  • 苍穹外卖日记
  • C:\Windows\WinSxS 目录详解
  • Python语言一键整理xhs评论 基于github的开源项目 MediaCrawler
  • MySQL 全文索引指南
  • Spring框架(AOP)
  • “openfeign“调用接口上传文件报错:Failed to deleted temporary file used for part [file]
  • 博士招生 | 香港大学 机器增强认知实验室 招收博士生/实习生/访问学生
  • 安卓11 12系统修改定制化_____修改系统默认域名解析规则 实现屏蔽广告 屏蔽应用更新等功能
  • CVE-2021-4300漏洞复现
  • css实现圆角+边框渐变+背景半透明
  • Camera相机人脸识别系列专题分析之十九:MTK ISP6S平台FDNode原生代码