java类加载器及tomcat为什么不用双亲委派

Java的类加载器体系以及Tomcat为何打破双亲委派模型,是理解Java类隔离机制和Web容器设计的关键。下面分别进行解释。


一、Java 类加载器与双亲委派模型

1. 类加载器层次结构

Java 默认提供了三个主要类加载器:

  • 启动类加载器(Bootstrap ClassLoader) :C++实现,负责加载<JAVA_HOME>/lib目录下的核心类库(如rt.jar),是所有类加载器的父类。
  • 扩展类加载器(Extension ClassLoader) :Java实现,负责加载<JAVA_HOME>/lib/ext目录下的扩展类库,父加载器为Bootstrap。
  • 应用类加载器(Application ClassLoader) :也称系统类加载器,负责加载用户类路径(ClassPath)下的类,父加载器为Extension。

2. 双亲委派模型的工作机制

当一个类加载器收到类加载请求时,它会先委托父加载器去加载 ,如果父加载器无法加载(抛出ClassNotFoundException),才由自己尝试加载。流程如下:

text

复制代码
请求 → 当前加载器 → 委派给父加载器 → ... → 最终到达Bootstrap
→ 若Bootstrap无法加载 → 逐级回退,由子加载器尝试加载

3. 为什么采用双亲委派?

  • 安全性 :防止用户自定义的类替换核心API(如java.lang.Object)。因为双亲委派会优先让Bootstrap加载,保证了核心类库的统一性。
  • 避免重复加载:确保同一个类在全系统中只被加载一次。

4. 加载过程?

类加载器负责将.class文件加载到JVM中,整个过程包括 加载(Loading)→ 连接(Linking)→ 初始化(Initialization) 三个主要阶段,其中连接又细分为 验证(Verification)→ 准备(Preparation)→ 解析(Resolution)


二、Tomcat 为什么要打破双亲委派?

Tomcat作为Web容器,需要同时部署多个Web应用,每个应用可能依赖不同版本的第三方库(如A应用使用Spring 4,B应用使用Spring 5),同时还要保证这些应用之间完全隔离 ,并且共享一些基础类库(如Servlet API、JSP API等)。如果完全遵循双亲委派,会导致以下问题:

  1. 无法隔离应用:在双亲委派下,所有应用的类都会由相同的AppClassLoader或其父加载器加载,不同应用的同名类(但版本不同)会发生冲突。
  2. 无法实现热部署:当重新部署一个应用时,需要卸载该应用的类。双亲委派中类一旦被父加载器加载,就无法被卸载。

因此,Tomcat必须打破双亲委派,自定义类加载器来满足Web容器的特殊需求。


三、Tomcat 的类加载器体系与打破机制

Tomcat设计了一套层次化的类加载器结构(以Tomcat 8为例):

text

scss 复制代码
Bootstrap
    │
    └── System (AppClassLoader)
            │
            └── Common
                    ├── Catalina
                    └── Shared
                            └── WebApp (每个Web应用一个实例)
  • Common :加载$CATALINA_BASE/lib下的公共类库,供Tomcat服务器和所有Web应用共享。
  • Catalina :加载Tomcat服务器内部实现所需的类(如catalina.jar),对Web应用不可见。
  • Shared:加载所有Web应用共享的类库(如自定义的公共库),对Tomcat服务器内部不可见。
  • WebApp :每个Web应用拥有独立的WebAppClassLoader,负责加载/WEB-INF/classes/WEB-INF/lib下的类。

Tomcat 如何打破双亲委派?

WebAppClassLoader 打破了传统的双亲委派顺序:它首先尝试自己加载 (即加载/WEB-INF/classes/WEB-INF/lib下的类),如果找不到,才委托父加载器(通常是Shared)加载。这样做的目的是:

  • 优先加载应用自身的类,实现应用之间的隔离。如果A应用和B应用有同名但不同版本的类,各自的WebAppClassLoader会独立加载,互不影响。
  • 仍允许共享某些基础类:当应用自身的类加载不到时,仍然可以向上委托,让Common或System加载JDK和Tomcat的基础类(如Servlet API),避免重复加载。

这种策略可以总结为:先自加载,后委派,与标准的双亲委派(先委派后自加载)正好相反。

其他打破点

  • CatalinaShared 也打破了双亲委派吗?它们通常遵循标准的双亲委派,因为Tomcat需要确保内部实现(Catalina)不会被Web应用意外覆盖。只有WebAppClassLoader是主要打破点。

四、为什么Tomcat可以打破双亲委派?

双亲委派模型是Java官方推荐的实现,但并非强制约束ClassLoader类允许子类重写loadClass()方法,从而改变加载顺序。Tomcat正是通过自定义类加载器(WebappClassLoader)重写了loadClass(),实现了优先自加载的逻辑。


五、总结

对比点 标准双亲委派 Tomcat WebAppClassLoader
加载顺序 先委托父类,后自加载 先自加载,后委托父类
目的 安全性、避免重复加载 应用隔离、支持热部署
类冲突 不允许同名类存在 允许不同应用有同名不同版本类

Tomcat打破双亲委派,本质是在隔离性与共享性之间找到平衡:既要让每个Web应用拥有独立的类空间,又要保证基础类库(如JDK、Servlet API)被所有应用共享,从而节省内存、避免冲突。这一设计也成为了其他Java Web容器(如Jetty、Undertow)的通用实践。

相关推荐
MegaDataFlowers2 小时前
快速上手Spring
java·后端·spring
小江的记录本2 小时前
【MyBatis-Plus】Spring Boot + MyBatis-Plus 进行各种数据库操作(附完整 CRUD 项目代码示例)
java·前端·数据库·spring boot·后端·sql·mybatis
左左右右左右摇晃2 小时前
Java 笔记--OOM产生原因以及解决方法
java·笔记
大傻^2 小时前
Spring AI Alibaba Function Calling:外部工具集成与业务函数注册
java·人工智能·后端·spring·springai·springaialibaba
逆境不可逃2 小时前
LeetCode 热题 100 之 33. 搜索旋转排序数组 153. 寻找旋转排序数组中的最小值 4. 寻找两个正序数组的中位数
java·开发语言·数据结构·算法·leetcode·职场和发展
码界奇点2 小时前
基于Spring Boot的医院药品管理系统设计与实现
java·spring boot·后端·车载系统·毕业设计·源代码管理
小旭95273 小时前
Spring MVC :从入门到精通(下)
java·后端·spring·mvc
夏语灬3 小时前
MySQL大小写敏感、MySQL设置字段大小写敏感
java
毕设源码-郭学长3 小时前
【开题答辩全过程】以 某地红十字会门户网站为例,包含答辩的问题和答案
java