欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > Java-51 深入浅出 Tomcat 手写 Tomcat 类加载机制 双亲委派机制 生命周期 插件化

Java-51 深入浅出 Tomcat 手写 Tomcat 类加载机制 双亲委派机制 生命周期 插件化

2025/6/22 0:17:20 来源:https://blog.csdn.net/w776341482/article/details/148780927  浏览:    关键词:Java-51 深入浅出 Tomcat 手写 Tomcat 类加载机制 双亲委派机制 生命周期 插件化

点一下关注吧!!!非常感谢!!持续更新!!!

🚀 AI篇持续更新中!(长期更新)

目前2025年06月13日更新到:
AI炼丹日志-28 - Audiblez 将你的电子书epub转换为音频mp3 做有声书,持续打造实用AI工具指南!📐🤖

💻 Java篇正式开启!(300篇)

目前2025年06月11日更新到:
Java-44 深入浅出 Nginx - 底层进程机制 Master Worker 机制原理 常用指令
MyBatis 已完结,Spring 已完结,深入浅出助你打牢基础!

📊 大数据板块已完成多项干货更新(300篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!
目前2025年06月13日更新到:
大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解

请添加图片描述

JVM类加载机制

JVM 的类加载机制(Class Loading Mechanism)是 Java 虚拟机中一个非常核心的部分,它决定了类从哪里来、怎么加载、什么时候初始化等一系列行为。下面我会从 整体流程、类加载器模型、双亲委派机制、类生命周期 等几个方面详细描述。

类加载整体流程

Java 类的加载过程可以分为 五个阶段(有些资料是六阶段,把“使用”也列进去):

  • 加载(Loading)
  • 验证(Verification)
  • 准备(Preparation)
  • 解析(Resolution)
  • 初始化(Initialization)

加载(Loading)

  • 把 .class 文件读入内存,生成一个 java.lang.Class 对象。
  • 由类加载器完成,可能来自本地磁盘、网络、甚至是动态生成的字节码。
  • 指定类的二进制数据的获取方式,不等同于实例化对象。

验证(Verification)

  • 确保字节码符合 JVM 规范,保证运行时安全。
  • 检查格式是否正确、语义是否符合规定、权限是否合法等。

准备(Preparation)

  • 为类的静态变量分配内存,并设置初始默认值(不是显式赋值)。

解析(Resolution)

  • 把常量池中的符号引用转换为直接引用。
  • 如:类名、字段名、方法签名 -> 实际地址。

初始化(Initialization)

  • 正式执行 () 方法(类构造器),也就是执行静态变量的初始化和静态代码块。
  • 这是类加载过程的最后一步,之后类才可以使用。

类加载器模型(ClassLoader)

JVM 中的类加载器负责把类加载进 JVM,并维持一个“类名-类实例”的映射表。

  • Bootstrap ClassLoader(启动类加载器):JVM 内置,用 C++ 实现,JAVA_HOME/lib 核心类,如 java.lang.*
  • Extension ClassLoader(扩展类加载器):加载扩展库,JAVA_HOME/lib/ext
  • App ClassLoader(应用类加载器):最常用,默认加载你的代码,classpath 路径下的类
  • 自定义 ClassLoader:开发者自定义实现,如热部署、解密等

JVM的类机制中有一个非常重要的角色叫做类加载器(ClassLoader),类加载器有自己的体系,JVM内置了几种类加载器,包括:
● 引导类加载器
● 扩展类加载器
● 系统类加载器

双亲委派机制(Parent Delegation Model)

  • 类加载器在加载类之前,会先把请求交给父类加载器,一直向上委托,直到 Bootstrap。
  • 只有当父类加载器无法加载,子加载器才会尝试加载。

这样做的原因是:

  • 防止核心类被“篡改”或“重复加载”,保证安全性和一致性。
  • 如:你不能加载一个伪造的 java.lang.String 类。

比如会进行这样的加载:

AppClassLoader -> ExtClassLoader -> BootstrapClassLoader

类的生命周期(包含类加载阶段)

被主动使用时才会触发类加载(尤其是初始化)

  • new 实例
  • 访问静态变量
  • 调用静态方法
  • 反射调用
  • 子类初始化

类卸载

  • JVM 不再使用某个类,并且加载它的 ClassLoader 被回收,才可能卸载该类(主要出现在 OSGi、Tomcat 这类容器中)。

类加载机制与热部署/插件化的关系

  • 热部署(如 Spring Boot DevTools)通常通过自定义 ClassLoader 隔离加载上下文。
  • 插件系统(如 IDEA 插件)也依赖于 ClassLoader 的命名空间隔离性。

常见场景

  • Tomcat热部署:每次发布使用新的 ClassLoader
  • SPI机制:基于 Thread.currentThread().getContextClassLoader()
  • 解密加载:重写 findClass 方法
  • 沙箱隔离:不同插件使用不同的 ClassLoader
  • AOP/热更新:动态修改或替换 Class 对象

图示内容

它们之间形成父子关系,通过Parent属性来定义这种关系,最终可以形成树形结构。

在这里插入图片描述

● 引导启动类加载器 BootstrapClassLoader:C++编写,加载Java核心库 java.,比如 rt.jar中的类,构造 ExtClassLoader 和 AppClassLoader
● 扩展类加载器 ExtClassLoader:Java编写,加载扩展库 JAVA_HOME/lib/ext 目录下的 jar 中的类,如 classpath 中的 jre,javax.
或者 java.ext.dir 指定位置中的类
● 系统类加载器 SystemClassLoader/AppClassLoader:默认的加载器,搜索环境变量classpath中指明的路径

在这里插入图片描述

另外:用户可以自定义类加载器(Java编写,用户自定义的加载器,可加载指定路径的 class 文件)
当JVM运行过程中,用户自定义了类加载器去加载某些类时,会按照下面的步骤(父类委托机制):
● 用户自己的类加载器,把加载请求传给父加载器,父加载器再传给其父加载器,一直到加载器树的顶层
● 最顶层的类加载器首先针对其特定的位置加载,如果加载不到就转交给子类
● 如果一直到底层的类加载都没有加载到,那么会抛出异常:ClassNotFoundException

因此,按照这个过程可以想到,如果同样在 classpath 指定的目录中和自己工作目录中存放相同的class,会优先加载 classpath 目录中的文件。

双亲委派机制

基本介绍

当某个类加载器需要加载某个.class文件时,它首先把这个任务托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。

机制作用

● 防止重复加载同一个 .class,通过委托机制向上面去问问,加载过了就不加载了,保证数据安全。
● 保证 .class 不能被篡改,通过委托方式,不会去篡改核心 .class,即使篡改也不会加载。即使加载了也不会同一个 .class 对象了。不同的加载器加载同一个.class也不是同一个.class对象。这样保证了class执行安全(如果子类加载器先加载,那么我们写一些与Java.lang包中基础类同名的类,然后再定义一个子类,这样整个应用使用的基础类就变成了我们自定义的类了)
Object类->自定义加载器(可能真正的Object类已经被修改了)

Tomcat的类加载机制

Tomcat 的类加载机制相对于 JVM的类加载机制做了一些改变,没有严格的遵从双亲委派机制,也可以说打破了双亲委派机制。
比如 Tomcat 下,webapps下部署了两个应用:
● app1/lib/a-1.0.jar com.wzk.Abc
● app2/lib/a-2.0jar com.wzk.Abc
不同版本的 Abc 类的内容是不同的,代码是不一样的

在这里插入图片描述

● 引导类加载器 和 扩展类加载器 的作用不变
● 系统类加载器正常情况下加载的是 CLASSPATH 下的类,但是 Tomcat 的启动脚本并未使用该变量,而是加载Tomcat启动的类,比如 Bootstrap.jar,通常在 catalina.bat 或者 catalina.sh 中指定,位于 CATALINA_HOME/bin 下。
● Common 通用类的加载器加载 Tomcat 使用以及应用通用的一些类,位于 CATALINA_HOME/lib下,比如 servlet-api.jar
● Catalina ClassLoader 用于加载器内部可见类,这样类应用程序不能访问
● Shared ClassLoader 用于加载应用程序共享类,这些类服务器不会依赖
● Webapp ClassLoader 每个应用程序都会有一个独一无二的 Webapp ClassLoader,他用来加载本应用程序的 /WEB-INF/classes 和 /WEB-INF/lib 下的类。

Tomcat 8.5

Tomcat 8.5 默认改变了严格的双亲委派机制:
● 首先从 Bootstrap ClassLoader 加载指定的类
● 如果未加载到,则从 /WEB-INF/classes 加载
● 如果未加载到,则从 /WEB-INF/*.jar 加载
● 如果未加载到,则依次从 System、Common、Shared 加载(在这最后一步,遵从双亲委派机制)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词