JVM 类加载器深度解析(含实战案例)

上期文章内容:JVM类加载过程详解:从字节码到内存的蜕变之旅


目录

一、类加载器的本质是什么?

二、类加载机制全景

1.1 三阶段生命周期

1.2 关键数据结构

三、类加载器体系架构

2.1 四层标准类加载器

2.2 类加载器树形结构

四、双亲委派模型

4.1 定义

4.2 核心算法与工作流程

4.2 设计价值

4.3 破坏条件与场景

五、实战开发指南

4.1 自定义类加载器模板

4.2 线程上下文类加载器

4.2.1 概念剖析

4.2.2 Spring框架中的深度应用

4.2.2.1 核心作用

4.2.2.2 实现原理

4.2.2.3 典型场景

4.2.3 开发注意事项

4.2.3.1 潜在陷阱

4.2.3.2 最佳实践


一、类加载器的本质是什么?

类加载器(ClassLoader) 是JVM的 核心组件之一,它的核心职责是:
将字节码文件(.class)动态加载到内存中,并转换为JVM可以执行的 Class 对象
简单来说,类加载器就是JVM的“搬运工”——把外部的类文件搬进内存,并生成对应的类结构。

二、类加载机制全景

1.1 三阶段生命周期

类加载过程分为三个阶段:

  1. 加载(Loading)
    • 通过全限定名获取字节流(支持网络/Native)
    • 转换为方法区结构
    • 创建 Class 对象作为入口
  2. 链接(Linking)
    • 验证(Verification):字节码合规性检查
    • 准备(Prepare):分配静态字段初始值
    • 解析(Resolve):符号引用转直接引用
  3. 初始化(Initialization)
    • 执行静态块和静态变量赋值

1.2 关键数据结构

  • 方法区:存储类元数据(JDK8后元空间替代)
  • Class对象:每个类唯一实例,包含:
private final ClassLoader classLoader;
private final String name;
private volatile Class superclass;
// ...其他成员

三、类加载器体系架构

2.1 四层标准类加载

类加载器责任范围实现方式
Bootstrap ClassLoaderJVM核心类库(rt.jar等)C++实现
Platform ClassLoader扩展类库(ext目录)Java实现
Application ClassLoader应用类路径(classpath)Java实现
Custom ClassLoader用户自定义加载需求继承ClassLoader实现

关键特性

  • 启动类加载器无父节点(返回null)
  • 所有上层类加载器均为下层父节点
  • 通过getParent()追溯加载链

2.2 类加载器树形结构

四、双亲委派模型

4.1 定义

双亲委派模型 是类加载器的协作规则:
当一个类加载器收到加载请求时,它不会自己处理,而是将请求依次传递给父类加载器,直到顶层启动类加载器。只有父类加载器无法找到时,子类加载器才会尝试加载。

4.2 核心算法与工作流程

protected Class<?> loadClass(String name, boolean resolve) {// ① 已加载检查Class<?> c = findLoadedClass(name);if (c == null) {// ② 委派父加载器if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}if (c == null) {// ③ 自己加载c = findClass(name);}}// ④ 解析类if (resolve) resolveClass(c);return c;
}
双亲委派模型执行流程

4.2 设计目标

  • 安全保障:防止核心API被篡改
  • 避免重复加载:统一管理类加载
  • 命名空间隔离:不同加载器加载同名类视为不同类

4.3 破坏条件与场景

破坏方式典型应用场景
重写loadClass()SPI框架(如JDBC驱动加载)
利用线程上下文类加载器Tomcat/WAS等应用服务器
父加载器为空指针自定义根加载器

五、实战开发指南

4.1 自定义类加载器模板

public class MyClassLoader extends ClassLoader {@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {// ① 添加类名校验逻辑(防止非法类加载)if (!name.startsWith("com.example")) {throw new ClassNotFoundException("Invalid class name: " + name);}byte[] bytes = loadBytesFromNetwork(name); //自定义加载逻辑return defineClass(name, bytes, 0, bytes.length);}private byte[] loadBytesFromNetwork(String className) {try {URL url = new URL("http://example.com/classes/" + className.replace('.', '/') + ".class");HttpURLConnection connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");int responseCode = connection.getResponseCode();if (responseCode != HttpURLConnection.HTTP_OK) {throw new IOException("Failed to load class: " + className);}ByteArrayOutputStream outputStream = new ByteArrayOutputStream();InputStream inputStream = connection.getInputStream();byte[] buffer = new byte[4096];int bytesRead;while ((bytesRead = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, bytesRead);}return outputStream.toByteArray();} catch (IOException e) {throw new ClassNotFoundException("Network error while loading class: " + name, e);}}
}

关键增强点

  1. 类名白名单校验(安全防护)
  2. 完整的网络请求实现(支持HTTP协议)
  3. 异常链处理(保留原始异常信息)

4.2 线程上下文类加载器

4.2.1 概念剖析

        线程上下文类加载器(Thread Context ClassLoader)是JVM提供的一种动态绑定机制,允许在运行期动态改变某个线程的类加载器。通过 Thread.currentThread().getContextClassLoader() 获取当前线程绑定的类加载器。

设计初衷
        解决传统双亲委派模型在某些场景下的局限性,典型案例如 SPI(Service Provider Interface)服务加载和多层容器架构(如Tomcat)。


4.2.2 Spring框架中的深度应用
4.2.2.1 核心作用

Spring通过上下文类加载器实现以下目标:

  1. 隔离性保障
    Web应用中可能存在多个第三方库版本冲突,通过为每个Web应用分配独立的上下文类加载器(如Tomcat的 WebAppClassLoader),可以实现类隔离。

  2. 灵活加载策略
    当Spring需要加载应用类时(而非核心框架类),它会优先使用当前线程的上下文类加载器,从而正确找到应用类路径中的类。

4.2.2.2 实现原理
  1. 类加载器切换
    Tomcat在启动Web应用时,会为每个应用线程设置上下文类加载器为对应的 WebAppClassLoader

  2. Spring的类加载逻辑
    Spring通过 ClassUtils.getDefaultClassLoader() 方法获取当前线程的上下文类加载器:

    public static ClassLoader getDefaultClassLoader() {ClassLoader cl = null;try {cl = Thread.currentThread().getContextClassLoader();} catch (IllegalStateException ex) { // Should not happen// fallback to system classloadercl = ClassLoader.getSystemClassLoader();}if (cl == null) {cl = ClassLoader.getSystemClassLoader();}return cl;
    }
4.2.2.3 典型场景

场景1:加载应用类
当Spring需要实例化 com.example.MyService 时:

// 使用上下文类加载器加载
Class<?> clazz = ClassUtils.forName("com.example.MyService", getClassLoader());
MyService instance = (MyService) clazz.getDeclaredConstructor().newInstance();

场景2:加载第三方SPI实现
JDBC驱动注册时:

DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
// DriverManager内部使用上下文类加载器加载驱动实现类

4.2.3 开发注意事项
4.2.3.1 潜在陷阱
  1. 类加载器泄漏
    长生命周期线程(如HTTP请求线程)未及时清除上下文类加载器,可能导致内存泄漏。

  2. 版本冲突
    不同线程设置不同的上下文类加载器时,需确保类强唯一性(避免同名类被不同加载器加载)。

4.2.3.2 最佳实践
  1. 使用范围限定
    仅在必要时修改上下文类加载器,并在操作完成后恢复:

    ClassLoader original = Thread.currentThread().getContextClassLoader();
    try {Thread.currentThread().setContextClassLoader(myClassLoader);// 执行需要自定义加载器的代码
    } finally {Thread.currentThread().setContextClassLoader(original);
    }
  2. 优先级控制
    在自定义类加载器中添加父加载器委托逻辑:

    @Override
    protected Class<?> loadClass(String name) throws ClassNotFoundException {try {return getParent().loadClass(name);} catch (ClassNotFoundException e) {return findClass(name);}
    }



码字不易,希望可以一键三连,我们下期文章再见!!!

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

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

相关文章

仿 Sora 之形,借物理模拟之技绘视频之彩

来自麻省理工学院、斯坦福大学、哥伦比亚大学以及康奈尔大学的研究人员携手开源了一款创新的3D交互视频模型——PhysDreamer&#xff08;以下简称“PD”&#xff09;。PD与OpenAI旗下的Sora相似&#xff0c;能够借助物理模拟技术来生成视频&#xff0c;这意味着PD所生成的视频蕴…

业务架构、数据架构、应用架构和技术架构

TOGAF(The Open Group Architecture Framework)是一个广泛应用的企业架构框架&#xff0c;旨在帮助组织高效地进行架构设计和管理。 TOGAF 的核心就是由我们熟知的四大架构领域组成:业务架构、数据架构、应用架构和技术架构。 企业数字化架构设计中的最常见要素是4A 架构。 4…

【开源免费】基于SpringBoot+Vue.JS善筹网站(JAVA毕业设计)

本文项目编号 T 205 &#xff0c;文末自助获取源码 \color{red}{T205&#xff0c;文末自助获取源码} T205&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

vue+elementplus创建初始化安装

项目创建初始化 D:\Tool\mysql\education_vue 这个路径下cmd 或打开vscode&#xff0c;把项目丢进code中打开 安装element plus Container 布局容器 | Element Plus npm install element-plus --save 把项目初始文件Homeview AboutView删了&#xff0c;Router index.js中删一…

Word接入DeepSeek(API的作用)

1.打开”Word”&#xff0c;点击“文件”。 2.点击“选项”。 3.点击“信任中心”——“信任中心设置”。 4. 勾选”启用所有宏“&#xff0c;点击”确定“。 5.点击“自定义功能区”&#xff0c;勾选上“开发工具”&#xff0c;点击“确定”。 6.返回“文件——开发工具“下的…

Macos机器hosts文件便捷修改工具——SwitchHosts

文章目录 SwitchHosts软件下载地址操作添加方案切换方案管理方案快捷键 检测 SwitchHosts SwitchHosts 是一款 Mac 平台上的免费软件&#xff0c;它可以方便地管理和切换 hosts 文件&#xff0c;支持多种 hosts 文件格式。 软件下载地址 SwitchHosts 操作 添加方案 添加 …

Python的那些事第二十三篇:Express(Node.js)与 Python:一场跨语言的浪漫邂逅

摘要 在当今的编程世界里,Node.js 和 Python 像是两个性格迥异的超级英雄,一个以速度和灵活性著称,另一个则以强大和优雅闻名。本文将探讨如何通过 Express 框架将 Node.js 和 Python 结合起来,打造出一个高效、有趣的 Web 应用。我们将通过一系列幽默风趣的实例和表格,展…

汽车免拆诊断案例 | 2010 款路虎揽胜车空调偶尔出风异常

故障现象  一辆2010款路虎揽胜车&#xff0c;搭载5.0 L发动机&#xff0c;累计行驶里程约为16万km。车主反映&#xff0c;接通空调开关后&#xff0c;有时出风忽大忽小&#xff0c;有时不出风&#xff0c;有时要等2 min左右才出风&#xff1b;有时两三天出现一次&#xff0c;…

Django项目之订单管理part1

一.前言 我们前面把django的常用知识点给讲完了&#xff0c;现在我们开始项目部分&#xff0c;项目是一个订单管理系统&#xff0c;我们同时也会在项目之中也会讲一些前面没有用到的知识点。 项目大概流程如下&#xff1a; 核心的功能模块&#xff1a; 认证模块&#xff0c;用…

低代码与 Vue.js:技术选型与架构设计

在当下数字化转型的浪潮中&#xff0c;企业对应用开发的效率和质量有着极高的追求。低代码开发平台的兴起&#xff0c;为企业提供了一条快速构建应用的捷径&#xff0c;而 Vue.js 作为热门的前端框架&#xff0c;与低代码开发平台的结合备受关注。如何做好两者的技术选型与架构…

LlamaFactory可视化模型微调-Deepseek模型微调+CUDA Toolkit+cuDNN安装

LlamaFactory https://llamafactory.readthedocs.io/zh-cn/latest/ 安装 必须保证版本匹配&#xff0c;否则到训练时&#xff0c;找不到gpu cuda。 否则需要重装。下面图片仅供参考。因为cuda12.8装了没法用&#xff0c;重新搞12.6 cudacudnnpytorch12.69.612.6最新&#xf…

【GPT】从GPT1到GPT3

every blog every motto: Although the world is full of suffering&#xff0c; it is full also of the overcoming of it 0. 前言 从GPT1 到GPT3 1. GPT1 论文&#xff1a; https://s3-us-west-2.amazonaws.com/openai-assets/research-covers/language-unsupervised/lan…

Jredis和SpringDataRedis学习笔记

jredis基础操作 jredis连接池 其中有个静态方法getJedis能够将练级池中的连接拿取出来并返回 通过setMaxWaitMitllis设置一个响应时间&#xff0c;如果连接池里面没有连接&#xff0c;那么请求连接方在等待超过响应时间时就会报错 springDataRedis 通过这样一个代码将redisTe…

【HarmonyOS Next】鸿蒙监听手机按键

【HarmonyOS Next】鸿蒙监听手机按键 一、前言 应用开发中我们会遇到监听用户实体按键&#xff0c;或者扩展按键的需求。亦或者是在某些场景下&#xff0c;禁止用户按下某些按键的业务需求。 这两种需求&#xff0c;鸿蒙都提供了对应的监听事件进行处理。 onKeyEvent 默认的…

vite调试node_modules下面插件

在使用vite进行开发的时候,我们可能想要修改node_modules中插件的源码.特别是集成一个SDK&#xff0c;需要调试去判断问题时&#xff0c;或者研究第三方源码时后; vite默认是走缓存的&#xff0c;所以当修改后不会看到你打印的日志&#xff0c;这个时候有几种方法可以选择; 方式…

大数据开发治理平台~DataWorks(核心功能汇总)

目录 数据集成 功能概述 使用限制 功能相关补充说明 数据开发 功能概述 数据建模 功能概述 核心技术与架构 数据分析 功能概述 数据治理 数据地图 功能概述 数据质量 功能概述 数据治理资产 功能概述 使用限制 数据服务 功能概述 数据集成 DataWorks的数据…

JAVA生产环境(IDEA)排查死锁

使用 IntelliJ IDEA 排查死锁 IntelliJ IDEA 提供了强大的工具来帮助开发者排查死锁问题。以下是具体的排查步骤&#xff1a; 1. 编写并运行代码 首先&#xff0c;我们编写一个可能导致死锁的示例代码&#xff1a; public class DeadlockExample {private static final Obj…

【DeepSeek】Mac m1电脑部署DeepSeek

一、电脑配置 个人电脑配置 二、安装ollama 简介&#xff1a;Ollama 是一个强大的开源框架&#xff0c;是一个为本地运行大型语言模型而设计的工具&#xff0c;它帮助用户快速在本地运行大模型&#xff0c;通过简单的安装指令&#xff0c;可以让用户执行一条命令就在本地运…

挑战一星期复现一个项目——安全帽项目

本项目为识别安全帽项目&#xff0c;基于yoloV5模型&#xff0c;接下来&#xff0c;我将一步一步展示我的完整复现过程以及遇到的问题和解决方案。 前言 我们在利用GPU进行深度学习的时候&#xff0c;都要去NVIDIA的官网下载CUDA的安装程序和cudnn的压缩包&#xff0c;然后再…

基于java新闻管理系统,推荐一款开源cms内容管理系统ruoyi-fast-cms

一、项目概述 1.1 项目背景 在信息高速流通的当下&#xff0c;新闻媒体行业每天都要处理和传播海量信息。传统的新闻管理模式依赖人工操作&#xff0c;在新闻采集、编辑、发布以及后续管理等环节中&#xff0c;不仅效率低下&#xff0c;而且容易出现人为失误。同时&#xff0…