目录
[一、先理解背景:Java 原生类加载器的局限](#一、先理解背景:Java 原生类加载器的局限)
[二、Tomcat 自定义类加载器的核心原因](#二、Tomcat 自定义类加载器的核心原因)
[1. 实现 Web 应用的类隔离](#1. 实现 Web 应用的类隔离)
[2. 支持热部署](#2. 支持热部署)
[3. 打破双亲委派模型,灵活控制类加载顺序](#3. 打破双亲委派模型,灵活控制类加载顺序)
[4. 精细化的资源加载控制](#4. 精细化的资源加载控制)
[三、Tomcat 类加载器的层级结构](#三、Tomcat 类加载器的层级结构)
一、先理解背景:Java 原生类加载器的局限
Java 原生的类加载器(Bootstrap、Extension、Application)遵循 双亲委派模型:子加载器加载类前,会先委托父加载器加载,只有父加载器加载不到时,子加载器才自己加载。这种模型的核心是 "安全" 和 "统一",但对于 Tomcat 这类 Web 容器来说,存在明显局限:
- 无法实现 Web 应用之间的类隔离 :如果所有 Web 应用都使用同一个 Application 类加载器,不同应用的同名类(如
com.example.User)会冲突; - 无法实现 热部署:原生类加载器加载类后,类实例会被 JVM 永久引用,无法卸载,也就无法在不重启 JVM 的情况下更新应用;
- 无法灵活控制 类加载优先级 :Web 应用中,
WEB-INF/lib和WEB-INF/classes的类需要优先于系统类加载器的类加载(比如应用自带的低版本 Spring 要覆盖 Tomcat 依赖的高版本),而双亲委派模型是 "父优先",无法满足。
二、Tomcat 自定义类加载器的核心原因
Tomcat 设计了一套层级化的自定义类加载器(核心是 WebappClassLoader),主要解决以下问题:
1. 实现 Web 应用的类隔离
Tomcat 为每个 Web 应用(WAR 包)创建一个独立的 WebappClassLoader 实例,不同应用的类加载器相互独立:
- 每个应用加载自己
WEB-INF/classes、WEB-INF/lib下的类,互不干扰; - 即使两个应用包含完全同名、不同实现的类(如
com.example.utils.Tool),也不会冲突,因为它们属于不同的类加载器,JVM 认为是不同的类; - 避免了 "一个应用的类污染整个容器" 的问题(比如应用 A 加载的类不会影响应用 B)。
2. 支持热部署
类加载器与加载的类是绑定的:卸载类加载器 = 卸载该加载器加载的所有类。Tomcat 的热部署逻辑就是:
- 停止某个 Web 应用时,销毁其对应的
WebappClassLoader实例; - 重新部署时,创建新的
WebappClassLoader实例,加载最新的类文件; - 整个过程无需重启 Tomcat 进程,实现应用的 "热更新"。
3. 打破双亲委派模型,灵活控制类加载顺序
Tomcat 对核心类(如 Servlet API)和应用类采用不同的加载策略:
- 核心类(Tomcat 自身类、Servlet API) :遵循双亲委派,优先由父加载器(
CommonClassLoader)加载,保证容器核心类的唯一性; - 应用类(WEB-INF 下的类) :不遵循双亲委派 ,优先由
WebappClassLoader自己加载(自己加载不到,再委托父加载器)。这个设计解决了 "应用依赖的类版本与容器冲突" 的问题:比如应用需要使用slf4j-1.7.jar,而 Tomcat 自带slf4j-1.8.jar,应用的WebappClassLoader会优先加载自己WEB-INF/lib下的 1.7 版本,避免冲突。
4. 精细化的资源加载控制
Tomcat 自定义加载器还扩展了类加载器的资源加载能力:
- 可以精准加载 Web 应用专属的资源(如
WEB-INF/resources下的配置文件); - 可以控制哪些类允许被加载、哪些类禁止被加载(比如限制应用加载 Tomcat 内部的核心类,提升安全性)。
三、Tomcat 类加载器的层级结构
Tomcat 的自定义类加载器分为多层,各司其职:
Bootstrap ClassLoader(JVM 核心):加载 JRE/lib 核心类;System ClassLoader:加载 Tomcat 启动脚本指定的系统类;Common ClassLoader:加载 Tomcat 全局共享的类(conf/catalina/lib);Catalina ClassLoader:加载 Tomcat 容器自身的类(不共享给应用);Shared ClassLoader:加载所有 Web 应用共享的类(可配置);WebappClassLoader:每个 Web 应用独立的加载器(核心自定义加载器);JspClassLoader:每个 JSP 文件独立的加载器(支持 JSP 热编译)。
总结
Tomcat 自定义类加载器的核心目的可总结为 3 点:
- 隔离性:实现不同 Web 应用之间、应用与容器之间的类隔离,避免类冲突;
- 灵活性:打破双亲委派模型的限制,按需控制类加载优先级,适配 Web 应用的依赖需求;
- 可维护性:支持应用热部署,无需重启容器即可更新应用,提升运维效率。