Tomcat是如何隔离Web应用的

2023-11-01

Tomcat通过自定义的类加载器WebAppClassLoader打破了双亲委托机制,目的就是为了优化加载Web应用目录下的类。Tomcat 作为 Servlet 容器,它负责加载我们Servlet 类,此外它还负责加载 Servlet 所依赖的 JAR 包。并且Tomcat 本身也是也是一个 Java 程序,因此它需要加载自己的类和依赖的 JAR 包。Tomcat 自定义了一个类加载器 WebAppClassLoader, 并且给每个 Web 应用创建 一个类加载器实例,每个 Context 容器负责创建和维护一个 WebAppClassLoader 加载器 实例。其实现的原理就是不同的类加载器实例加载的类被认为是不同的类,即使它们的类名 相同(不同类加载器实例加载的类是互相隔离的)

Tomcat是如何隔离Web应用的? Tomcat 自定义了一个类加载器 WebAppClassLoader, 并且给每个 Web 应用创建 一个类加载器实例,每个 Context 容器负责创建和维护一个 WebAppClassLoader 加载器 实例。其实现的原理就是不同的类加载器实例加载的类被认为是不同的类,即使它们的类名 相同(不同类加载器实例加载的类是互相隔离的)

Tomcat 的自定义类加载器 WebAppClassLoader 打破了双亲委托机制,它首先自己 尝试去加载某个类,如果找不到再代理给父类加载器,其目的是优先加载 Web 应用自己定 义的类。具体实现就是重写 ClassLoader 的两个方法:findClass 和 loadClass。 在 findClass 方法里,主要有三个步骤:


1. 先在 Web 应用本地目录下查找要加载的类。
2. 如果没有找到,交给父加载器去查找,它的父加载器就是上面提到的系统类加载器
AppClassLoader。
3. 如何父加载器也没找到这个类,抛出 ClassNotFound 异常。

loadClass 方法稍微复杂一点,主要有六个步骤:

1. 先在本地 Cache 查找该类是否已经加载过,也就是说 Tomcat 的类加载器是否已
经加载过这个类。
2. 如果 Tomcat 类加载器没有加载过这个类,再看看系统类加载器是否加载过。
3. 如果都没有,就让ExtClassLoader去加载,这一步比较关键,目的防止 Web 应用
自己的类覆盖 JRE 的核心类。因为 Tomcat 需要打破双亲委托机制,假如 Web 应用
里自定义了一个叫 Object 的类,如果先加载这个 Object 类,就会覆盖 JRE 里面的
那个 Object 类,这就是为什么 Tomcat 的类加载器会优先尝试用 ExtClassLoader
去加载,因为 ExtClassLoader 会委托给 BootstrapClassLoader 去加载,
BootstrapClassLoader 发现自己已经加载了 Object 类,直接返回给 Tomcat 的类
加载器,这样 Tomcat 的类加载器就不会去加载 Web 应用下的 Object 类了,也就
避免了覆盖 JRE 核心类的问题。

4. 如果 ExtClassLoader 加载器加载失败,也就是说 JRE 核心类中没有这类,那么就
在本地 Web 应用目录下查找并加载。
5. 如果本地目录下没有这个类,说明不是 Web 应用自己定义的类,那么由系统类加
载器去加载。这里请你注意,Web 应用是通过Class.forName调用交给系统类加载
器的,因为Class.forName的默认加载器就是系统类加载器。
6. 如果上述加载过程全部失败,抛出 ClassNotFound 异常。

Tomcat类加载器结构:

Tomcat自定义了多个类加载器,CommonClassLoader、CatalinaClassLoader、 SharedClassLoader和WebappClassLoader则是Tomcat自己定义的类加载器,它们分别 加载/common/、/server/、/shared/和/WebApp/WEB-INF/中的Java类库。

其中 WebApp类加载器和Jsp类加载器通常会存在多个实例,每一个Web应用程序对应一个 WebApp类加载器,每一个JSP文件对应一个Jsp类加载器

CommonClassLoader : Tomcat 通用类加载器, 加载的资源可被 Tomcat 和
所有的 Web 应用程序共同获取
CatalinaClassLoader : Tomcat 类加载器, 加载的资源只能被 Tomcat 获取(但
所有 WebappClassLoader 不能获取到 catalinaLoader 加载的类)
SharedClassLoader : Tomcat 各个Context的父加载器, 这个类是所有
WebappClassLoader 的父类, sharedLoader 所加载的类将被所有的
WebappClassLoader 共享获取
WebappClassLoader : 每个Context 对应一个 WebappClassloader, 主要用
于加载 WEB-INF/lib 与 WEB-INF/classes 下面的资源

在 JVM 的实现中有一条隐含的规则,默认情况下,如果一个类由类加载器 A 加载,那 么这个类的依赖类也是由相同的类加载器加载。比如 Spring 作为一个 Bean 工厂,它需要 创建业务类的实例,并且在创建业务类实例之前需要加载这些类。 思考:如果spring作为共享第三方jar包,交给SharedClassLoader加载,但是业务类 在web目录下,不在SharedClassLoader的加载路径下,那spring如何加载web应用目录下 的业务bean呢? Tomcat 为每个 Web 应用创建一个 WebAppClassLoarder 类加载器,并在启动 Web 应用的线程里设置线程上下文加载器,这样 Spring 在启动时就将线程上下文加载器 取出来,用来加载 Bean。

线程上下文加载器是一种类加载器传递机制,因为这个类加载器保存在线程私有数据 里,只要是同一个线程,一旦设置了线程上下文加载器,在线程后续执行过程中就能把这个 类加载器取出来用。

Thread.currentThread().getContextClassLoader()

线程上下文加载器不仅仅可以用在 Tomcat 和 Spring 类加载的场景里,核心框架类需 要加载具体实现类时都可以用到它,比如我们熟悉的 JDBC 就是通过上下文类加载器来加载 不同的数据库驱动的

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Tomcat是如何隔离Web应用的 的相关文章

随机推荐

  • UE4 Pak打包、挂载、加载

    首先 必须得明确的一点就是如果想要加载Pak内资源 那么这些资源必须是经过Cook的 如果打包的是未Cook的资源 那么即使Pak挂载成功 也不可能会成功加载Pak内资源 不知道怎么生成Cook资源 可以看我前一篇 UE4 Cook指定平台
  • javascript各种类型数据在表达式中转换成布尔型值的规则总结

    javascript中有5种数据类型 分别为 Undefined Boolean Object Number String 这几类型的数据 当他们处在表达式里面的时候 js解析器会自动将其转换成布尔值来决定当前的条件究竟符合哪个逻辑分支 当
  • MySQL5.6.11安装步骤(Windows7 64位)

    原文地址 http www cnblogs com happyty p 4131686 html 1 下载MySQL Community Server 5 6 21 注意选择系统类型 32位 64位 2 解压MySQL压缩包 将以下载的My
  • Nuxt3+Vite批量引入图片

    通过计算属性获取images文件夹所有层级下所有静态资源
  • WriteError Resulting document after update is larger than 16777216

    MongoDB插入数据失败 问题描述 发生异常 WriteError Resulting document after update is larger than 16777216 full error index 0 code 17419
  • tvm的一个大体介绍

    TVM的一个大体介绍 导入模型 模型转换到relay 转换到 tensor expression TE 自动优化调度 模型编译 转换到TIR tensor IR 编译器编译到机器码 导入模型 可以支持从tf pytorch 或者onnx框架
  • 音频基础学习三——声音的时频谱

    文章目录 前言 时域与频域 1 什么是时域 2 什么是频域 3 一张图理解时域和频域 4 意义 总结 前言 在上一篇文章中 我们了解到 任何重复的波形都可以分解为含有基波频率和一系列为基波倍数的谐波的正弦波分量 同时记录了一些基本的波形 本
  • python 用eclipse编辑器编写唐僧打白骨精

    python 用eclipse编辑器编写唐僧打白骨精 coding utf 8 Created on 2019年7月10日 note 唐僧打白骨精 author LSW version 3 0 YaoGj 10 妖怪攻击力 YaoSm 10
  • 如何用echarts画一个好看的饼图

    前言 最近有个需求 需要绘制一个饼图 为此我根据这次需求来整理了一下关于 echarts 饼图绘制的一些知识点 在这次需求中我需要用到的属性我会详细讲解 其他的属性我会粗略地说一下 并加入其他博主的文章的跳转 综合案例在后续博客中更新 注意
  • android动画不占cpu如何实现,【实战总结】帧动画调优实践

    原标题 实战总结 帧动画调优实践 原文链接 https www zybuluo com avenwu note 876161 APP架构师整理发布 转载请联系作者获得授权 1 背景 在做动画的时候我们有很多选择方案 最常见的是Android
  • JBPM4—请假流程

    1 流程图 2 流程配置文件
  • 数据分析之——Adventure项目分析

    文章目录 数据分析 Adventure项目分析 内容摘要 一 项目简介 二 分析思路 三 分析过程 0 数据准备及清洗 1 导入模块 2 简单了解数据 3 数据处理 1 整体销售表现 1 自行车整体销售量表现 2 自行车整体销售金额表现 3
  • 直流电源线缆 高速电缆 分类

    线缆分类 直流电源线缆采用整长发货 现场需要根据实际使用长度进行截取并现场制作电源线 直流电源线缆包括 48V电源线和电源地线RTN 连接配电盒与配电屏的直流电源线缆的长度和接线端子需要根据工勘确定 直接与电源模块连接的直流电源线缆为OT端
  • VUE常用的自定义指令

    v directives 基于 vue 的自定义指令集合 包含 复制粘贴指令 v copy 长按指令 v longpress 输入框防抖指令 v debounce 禁止表情及特殊字符 v emoji 图片懒加载 v LazyLoad 权限校
  • mysql的分组group by

    文章目录 一 介绍 1 分组查询的内容 2 多字段分组 3 将查询内容连接group concat 4 有条件的分组查询having 一 介绍 将某个字段的相同值分为一组 分组查询的结果强调的是一个整体 每组内容只显示一行 分组查询的内容一
  • C语言-蓝桥杯-基础练习 矩阵乘法

    问题描述 给定一个N阶矩阵A 输出A的M次幂 M是非负整数 例如 A 1 2 3 4 A的2次幂 7 10 15 22 输入格式 第一行是一个正整数N M 1 lt N lt 30 0 lt M lt 5 表示矩阵A的阶数和要求的幂数 接下
  • Python爬虫之Js逆向案例(12)-知乎答案批量获取保存到CSV文件

    声明 知乎答案批量获取分析仅用于研究和学习 如有侵权 可联系删除 大家好 本期分享的内容是一个关于批量获取知乎答案的案例 本案例的重点是教大家在写爬虫时如何更规范的去编写自己的爬虫 场景是这样的 最近在帮一位同学排查几个爬虫问题 于是乎我三
  • Pandas实战-Series对象

    本文将主要介绍以下内容 1 Series概述 2 从Python对象创建Series 3 读取最前面和最后面的数据 4 数学运算 5 将Series传递给Python的内置函数 Series是Pandas的两个主要数据结构之一 它是用于存储
  • 强化学习-稀疏奖励

    稀疏奖励 出现的原因 训练agent的时候 多数时候agent获取不到reward 没有奖励或惩罚 乱探索什么也学不到 这是不是奖惩设置不合理的一种体现 解决方案 Reward Shaping Reward shaping 的思想是说环境有
  • Tomcat是如何隔离Web应用的

    Tomcat通过自定义的类加载器WebAppClassLoader打破了双亲委托机制 目的就是为了优化加载Web应用目录下的类 Tomcat 作为 Servlet 容器 它负责加载我们Servlet 类 此外它还负责加载 Servlet 所