衣服颜色管理
52.58M · 2026-03-22
Java的类加载器体系以及Tomcat为何打破双亲委派模型,是理解Java类隔离机制和Web容器设计的关键。下面分别进行解释。
Java 默认提供了三个主要类加载器:
<JAVA_HOME>/lib目录下的核心类库(如rt.jar),是所有类加载器的父类。<JAVA_HOME>/lib/ext目录下的扩展类库,父加载器为Bootstrap。当一个类加载器收到类加载请求时,它会先委托父加载器去加载,如果父加载器无法加载(抛出ClassNotFoundException),才由自己尝试加载。流程如下:
text
请求 → 当前加载器 → 委派给父加载器 → … → 最终到达Bootstrap
→ 若Bootstrap无法加载 → 逐级回退,由子加载器尝试加载
java.lang.Object)。因为双亲委派会优先让Bootstrap加载,保证了核心类库的统一性。类加载器负责将.class文件加载到JVM中,整个过程包括 加载(Loading)→ 连接(Linking)→ 初始化(Initialization) 三个主要阶段,其中连接又细分为 验证(Verification)→ 准备(Preparation)→ 解析(Resolution)
Tomcat作为Web容器,需要同时部署多个Web应用,每个应用可能依赖不同版本的第三方库(如A应用使用Spring 4,B应用使用Spring 5),同时还要保证这些应用之间完全隔离,并且共享一些基础类库(如Servlet API、JSP API等)。如果完全遵循双亲委派,会导致以下问题:
因此,Tomcat必须打破双亲委派,自定义类加载器来满足Web容器的特殊需求。
Tomcat设计了一套层次化的类加载器结构(以Tomcat 8为例):
text
Bootstrap
│
└── System (AppClassLoader)
│
└── Common
├── Catalina
└── Shared
└── WebApp (每个Web应用一个实例)
$CATALINA_BASE/lib下的公共类库,供Tomcat服务器和所有Web应用共享。catalina.jar),对Web应用不可见。/WEB-INF/classes和/WEB-INF/lib下的类。WebAppClassLoader 打破了传统的双亲委派顺序:它首先尝试自己加载(即加载/WEB-INF/classes和/WEB-INF/lib下的类),如果找不到,才委托父加载器(通常是Shared)加载。这样做的目的是:
这种策略可以总结为:先自加载,后委派,与标准的双亲委派(先委派后自加载)正好相反。
双亲委派模型是Java官方推荐的实现,但并非强制约束。ClassLoader类允许子类重写loadClass()方法,从而改变加载顺序。Tomcat正是通过自定义类加载器(WebappClassLoader)重写了loadClass(),实现了优先自加载的逻辑。
| 对比点 | 标准双亲委派 | Tomcat WebAppClassLoader |
|---|---|---|
| 加载顺序 | 先委托父类,后自加载 | 先自加载,后委托父类 |
| 目的 | 安全性、避免重复加载 | 应用隔离、支持热部署 |
| 类冲突 | 不允许同名类存在 | 允许不同应用有同名不同版本类 |
Tomcat打破双亲委派,本质是在隔离性与共享性之间找到平衡:既要让每个Web应用拥有独立的类空间,又要保证基础类库(如JDK、Servlet API)被所有应用共享,从而节省内存、避免冲突。这一设计也成为了其他Java Web容器(如Jetty、Undertow)的通用实践。