JVM 类加载器详解 - 实践

news/2025/9/24 12:19:33/文章来源:https://www.cnblogs.com/tlnshuju/p/19108945

JVM 类加载器详解 - 实践

2025-09-24 12:16  tlnshuju  阅读(0)  评论(0)    收藏  举报

JVM 类加载器详解

如果要确定两个类是否相同,必须满足以下三点:

  1. 同路径
  2. 同名
  3. 由同一个类加载器创建

即使是同路径同名的 class 类,要是被不同的类加载器加载那也是不同的

一、类加载器分类及作用

JVM 类加载器分为四类,按层级从上到下依次为:

类加载器作用加载路径/范围实现语言
启动类加载器(Bootstrap ClassLoader)加载 JVM 核心类库(如 java.lang.*java.util.*),唯一不继承 ClassLoader 的加载器JAVA_HOME/jre/lib 下的核心 jar 包(如 rt.jarC/C++
扩展类加载器(Extension ClassLoader)加载 JVM 扩展类库(如 javax.*JAVA_HOME/jre/lib/ext 目录下的 jar 包Java
应用程序类加载器(Application ClassLoader)加载用户类路径(ClassPath)下的类(如项目代码、第三方依赖)-classpath-cp 指定的路径Java
自定义类加载器(Custom ClassLoader)用户自定义类加载逻辑(如热部署、网络加载、加密类加载)由用户代码搭建Java

二、双亲委派机制

1. 核心流程

当类加载器收到加载请求时,按以下步骤处理:

  1. 向上委派
    不直接加载类,而是先委派父类加载器处理。
  2. 向下尝试
    若父类加载器无法完成加载(在自己的搜索范围内找不到类),子类加载器才会尝试加载。
2. 流程示例

具体实现依赖于**ClassLoader.loadClass()**

protected Class<
?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// 1. 检查是否已加载
Class<
?> c = findLoadedClass(name);
if (c == null) {
try {
// 2. 先委派父加载器加载
if (parent != null) {
c = parent.loadClass(name, false);
// 递归调用父加载器
} else {
// 父加载器为 null,表示到达 Bootstrap 类加载器
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 父加载器加载失败,继续向下执行
}
if (c == null) {
// 3. 父加载器未找到,由当前类加载器加载
c = findClass(name);
}
}
return c;
}
}
  • 用户自定义类 MyClass 的加载过程:
    1. Application ClassLoader → 委派给 Extension ClassLoader
    2. Extension ClassLoader → 委派给 Bootstrap ClassLoader
    3. Bootstrap ClassLoader 未找到 MyClass → 返回 Extension ClassLoader
    4. Extension ClassLoader 未找到 MyClass → 返回 Application ClassLoader
    5. Application ClassLoader 在 ClassPath 中找到并加载 MyClass
3. 核心意义
  • 避免重复加载:确保类在 JVM 中唯一(由父加载器优先加载)。对于避免重复加载,双亲委派通过委派链确保每个类由最顶层的父加载器优先尝试加载,如果已经加载过,就直接返回,不会再让子加载器处理。
  • 保护核心类安全:防止用户自定义同名类(如 java.lang.String)覆盖 JVM 核心类。类加载过程会由启动类加载器强制优先加载核心类,加载后就会直接返回,所以子类无法通过自定义同名类来覆盖核心类

三、打破双亲委派机制的场景

1. 经典场景
  • SPI 服务发现
    JDBC 的 DriverManager 需要加载不同厂商的数据库驱动(如 MySQL、Oracle)。
    • 问题:启动类加载器想要加载不在自己加载路径下(范围内)的类,即跨级加载子加载器的类

      核心类 DriverManager(由 Bootstrap ClassLoader 加载)需调用第三方驱动的实现类(由 Application ClassLoader 加载,其位置并不在启动类加载器的扫描路径下),但双亲委派机制禁止父加载器访问子加载器的类。

    • 解决方案:将类加载器切换为线程上下文类加载器,将加载权临时交给子类加载器。

2. 如何打破双亲委派?
  • 重写 loadClass() 方法
    自定义类加载器不委派父加载器,直接加载类。
  • 线程上下文类加载器
    通过 Thread.currentThread().setContextClassLoader() 临时切换类加载器。

以下是java发展历程中的三次打破双亲委派机制

第一次破坏:JDK 1.2 之前的“远古时代”
  • 背景
    在 JDK 1.2 引入双亲委派模型之前,类加载器的实现没有统一规范。开发者通常直接重写 loadClass() 方法,直接实现类加载逻辑,​未形成层级委派机制
  • 问题
    • 类加载逻辑混乱,容易重复加载或覆盖核心类。
    • 缺乏统一的委派规则,导致类加载器之间的协作困难。
  • JDK 1.2 的改进
    • 正式提出双亲委派模型,规范类加载流程。
    • 建议开发者仅重写 findClass()
      loadClass() 方法默认实现委派逻辑,而 findClass() 仅负责具体类查找(如从自定义路径加载字节码)。开发者只需重写 findClass() 即可实现扩展,无需破坏委派机制。
  • 意义
    通过约束开发者仅扩展 findClass(),避免直接干预委派流程,从而维护双亲委派的核心规则。

第二次破坏:模型自身的缺陷(基础类型回调用户代码)
  • 背景
    双亲委派模型要求父加载器优先加载类,但某些场景下,​父加载器加载的类需要调用子加载器加载的构建类,导致无法直接借助委派机制实现。

  • 典型案例

    • JDBC SPI(如 DriverManager):

      • DriverManager(由 Bootstrap ClassLoader 加载)需要加载不同数据库厂商的 Driver 实现类(由 Application ClassLoader 加载)。
    • 按双亲委派规则,父加载器(Bootstrap)无法直接访问子加载器(Application)的类,导致驱动无法加载。

  • 解决方案

    • 线程上下文类加载器(TCCL)
      通过 Thread.currentThread().setContextClassLoader() 将类加载器切换为子加载器(如 Application ClassLoader),使父加载器代码可间接访问子加载器的类。
  • 意义
    通过打破双亲委派,解决了核心库(如 JDBC)需要动态扩展的难题,但需谨慎使用以避免安全风险。


第三次破坏:动态性需求(热替换、模块热部署)
  • 背景
    现代应用对 ​动态性的要求需要更灵活的类加载机制,而双亲委派的层级化模型无法满足。

  • 典型案例

    Tomcat 热部署:

    • 每个 Web 应用使用独立的 WebappClassLoader,重启应用时直接替换类加载器,实现代码热替换。
  • 意义
    牺牲双亲委派的部分安全性,换取系统的高灵活性和动态性,适应云原生、微服务等现代架构需求。


四 、自定义类加载器

使用场景
  • 想加载非 classpath 随意路径中的类文件
  • 借助接口来使用实现,希望解耦时,常用在框架设计和SPI思想
  • 这些类希望予以隔离,不同应用的同名类都可以加载违背双委机制的意义1),不冲突,常见于 tomcat 容器就是(其实就
步骤
  1. 继承 ClassLoader 父类
  2. 要遵从双亲委派机制,重写findClass技巧(不是重写 loadClass 方法,否则不会走双亲委派机制)
  3. 读取类文件的字节码,调用父类的 defineClass 方法来加载类
  4. 使用者调用该类加载器的 loadClass 方法

补充问题

为什么tomcat要自定义类加载器?

  1. 无法隔离不同web应用的类

    比如两个web应用分别依赖同一个库的不同版本(如 log4j 1.x 和 log4j 2.x)

    若遵循双亲委派:

    1. 父加载器加载 log4j-1.2.17.jar
    2. 应用 2 的类加载器委托父加载器时,发现 Log4j 类已加载,被迫使用旧版本,导致兼容性问题。

    打破双亲委派后:

    1. 应用 2 的 WebApp ClassLoader 优先加载自己的 log4j-2.14.1.jar
    2. 两个应用利用各自版本的 Log4j,互不干扰。
  2. 无法支持热部署

    Web 应用要求在不重启 Tomcat 的情况下重新加载类,但双亲委派模型下,一旦类被父加载器加载,无法卸载和重新加载。

    • tomcat内部是启用WebApp ClassLoader,每个web应用都会独立使用一个类加载器

    • 委派给父加载器就是在加载类时,先检查本地缓存,再尝试自己加载,然后才

    • 这样在 Web 应用重启时,Tomcat 会销毁旧的 WebApp ClassLoader,并创建新的类加载器重新加载类,旧的类可被 GC 回收,实现热部署。

jvm中类加载后怎么卸载,什么时候卸载?

卸载类即该类的Class 对象被 GC,卸载类必须满足3个要求:

  1. 该类的所有的实例对象都已被 GC,也就是说堆不存在该类的实例对象
  2. 该类没有在其他任何地方被引用
  3. 该类的类加载器的实例已被 GC,一般是可替换类加载器的场景

注:

  • 类加载器本身必须被垃圾回收,其加载的类才被卸载
  • 在 JVM 生命周期类,由 JVM 自带的类加载器加载的类是不会被卸载的,自定义的类加载器加载的类是可能被卸载。因为 JVM 会始终引用启动、扩展、体系类加载器,这些类加载器始终引用它们所加载的类,这些类始终是可及的

因此回到困难本身:

1.只有类加载器被卸载,类没有实例且class对象没有被引用才会被卸载

三个条件全部满足时被GC回收就是2.卸载方式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/915693.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

石碣做网站优化偷wordpress模板

wildfly管理控制台红帽JBoss企业应用程序平台&#xff08;EAP&#xff09;和WildFly具有共生关系 。 简而言之&#xff0c;红帽JBoss企业应用程序平台&#xff08;JBoss EAP&#xff09;保留了WildFly社区项目&#xff08;以前称为JBoss Application Server&#xff09;的所有创…

音乐网站制作教程步骤wordpress登陆后查看

李宗盛有首歌的歌词里写到&#xff1a;「工作是容易的&#xff0c;赚钱是困难的」。乍一听感觉有点矛盾&#xff0c;工作的一个重要结果不就是赚钱么&#xff0c;为什么工作容易赚钱却难&#xff1f;但仔细一想就恍然其中想表达的意思了。 工作的本质是出售劳动价值&#xff0c…

网站域名备案需要什么罗湖营销型网站建设

RPC和 HTTP是两种常见的通信方式&#xff0c;它们在设计目标、使用场景和技术实现上有显著区别。以下是它们的详细对比&#xff1a; 1. 定义与核心思想 特性RPCHTTPRemote Procedure Call远程过程调用HyperText Transfer Protocol超文本传输协议定义一种协议或框架&#xff0…

昌平哪有做网站的公司比较大网站建设公司

&#x1f6eb;更多ssm知识见SSM_面向CRUD编程专栏 &#x1f695;本博客总结自黑马程序员的ssm框架视频 &#x1f692;博主对于该知识尚在学习阶段 &#x1f684;如果发现存在问题请毫不吝啬的指出 &#x1f680;&#x1f680;扎哇太枣糕的博客主页&#x1f680;&#x1f680; 目…

网站建设推广安徽国内专业网站设计

删除的场景&#xff1a; 解决思路&#xff1a; 1、计算操作后的总页数 2、删除成功之后的总页数与当前总页数进行比较 3、如果删除成功之后的总页数比小于当前总页数&#xff0c;需要把当前页码减去1&#xff1b;否则&#xff0c;直接进行列表数据的请求 代码实现 /*总条数…

中国做网站的公司新手网页制作

2022-01-25 更新&#xff1a;博客新地址&#xff1a;https://www.itbob.cn/&#xff0c;文章距上次编辑时间较远&#xff0c;部分内容可能已经过时&#xff01; 文章目录● 前言● 注册 Cloudflare● 添加站点● 修改DNS● 开启 HTTPS● 重定向强制 HTTPSHTTP&#xff08;超文本…

Unity小游戏接入抖音敏感词检测 - 指南

Unity小游戏接入抖音敏感词检测 - 指南2025-09-24 12:04 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !…

SQLite的并发问题

转载自:C# 下 SQLite 并发操作与锁库问题的 5 种解决方案_51CTO博客_sqlcipher c# SQLite是轻量级的数据库,可用于嵌入式设备,仅需几百KB的内存即可工作,整个数据库存储在单一文件中,便于管理,迁移,备份。无需繁…

域渗透靶场-vulntarget-a综合靶场

nmap发现开放80端口浏览器访问,是通达oa可以搜索poc或者使用oa利用工具拿到shell 通过账号admin 密码滞空,进入后台我们这里使用通达OA 11.2 后台getshell 点击系统管理 -> 系统参数设置 -> OA服务设置 找到We…

在线设计logo的网站小程序开发和app开发差别

1、读取哈使用方法不同SAP内存使用SET/GET parameters方法&#xff1b;ABAP内存使用 EXPORT 和 IMPORT 方法&#xff1b;2、共享范围不同SAP内存可以被所有的主session访问&#xff0c;内存数据可以同一个session中不同程序之间&#xff0c;或者不同session之间&#xff1b;AB…

现在的网站开发用什么技术南宁百度seo

简介&#xff1a; MaxCompute 是面向分析的企业级 SaaS 模式云数据仓库&#xff0c;以 Serverless 架构提供快速、全托管的在线数据仓库服务&#xff0c;消除了传统数据平台在资源扩展性和弹性方面的限制&#xff0c;最小化用户运维投入&#xff0c;使您可以经济并高效的分析处…

温州网站 公司做网站招标

一、源码特点 idea 开发 SSM 学员信息管理系统是一套完善的信息管理系统&#xff0c;结合SSM框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff…

网站建设主要学什么软件济宁哪里有网站建设

五层&#xff1a; 应用层&#xff1a;应用层是最高层&#xff0c;负责为用户提供网络服务和应用程序。在应用层&#xff0c;用户应用程序与网络进行交互&#xff0c;发送和接收数据。典型的应用层协议包括HTTP&#xff08;用于网页浏览&#xff09;、SMTP&#xff08;用于电子邮…

数组和链表读取、插入、删除以及查找的区别

数组和链表是两种常见的数据结构,它们在读取、插入、删除操作上有显著差异,下面详细说明: 1. 读取(访问)操作数组: 数组是连续的内存空间,元素按索引(下标)存储,因此可以通过索引直接访问任意位置的元素,时…

day 09 课程

day 09 课程课程:https://www.bilibili.com/video/BV1o4411M71o/?spm_id_from=333.788.videopod.episodes&p=168 9.1 了解函数———————————————————————————————————————…

在K8S中,日志分析工具有哪些可以与K8S集群通讯?

在Kubernetes中,日志分析工具与集群的通信方式多样,可以根据部署位置和采集方式分为几大类。以下是主流工具的详细分类和介绍: 📊 日志分析工具分类概览 graph TDA[K8S日志分析工具] --> B1[集群内部部署]A --…

在K8S中,网络通信模式有哪些?

好的,这是一个非常核心的问题。Kubernetes 的网络模型是一个复杂的体系,但我们可以将其分解为几个清晰的层次来理解。 Kubernetes 网络通信模式可以分为四大类,下图清晰地展示了这四类通信的全景:A[Kubernetes 网络…

中山网站代运营python nginx做网站

Creator 版本&#xff1a; 3.8.2 目标平台&#xff1a;小游戏开发 压缩后 我不知道别人压缩几百kb是怎么做到的。不过哪个要钱。 我这个技巧不用花钱。 论坛有教程但是没有教详细怎么做。 开整&#xff01; 做一个空白的场景。然后写一个load脚本。load主场景。 从代码可…

厦门网站建设a建筑设计工资一般多少

TCP客户端数据通信 文章目录 TCP客户端数据通信1、软件准备2、硬件准备3、仿真电路原理图4、仿真代码实现5、仿真结果本文将介绍Arduino在Protues仿真环境中作为TCP客户端,如何与TCP服务器进行数据通信。 1、软件准备 1)Arduino IDE或 VSCode + PlatformIO 2)Proteus电路仿…

一文教你搞定PASS 2025:样本量计算神器安装到使用全流程

软件介绍 PASS 2025 是用于效能分析和样本量估计的统计软件包,它在前版本基础上新增了37项样本量计算程序,涵盖医学研究、社会科学调查、工程实验等多种复杂统计场景。新增的Logrank类检验样本量计算程序,能精准计算…