类加载机制详解:双亲委派模型与打破它的方式

在复杂的 Java 系统中,类加载是最基础却常被忽略的一环。理解 JVM 的类加载机制,特别是 双亲委派模型(Parent Delegation Model),是我们深入掌握热部署、插件机制、ClassLoader 隔离、ClassNotFound 错误等问题的关键。

一、为什么你必须了解类加载机制?

想象几个场景:

  • 使用 Tomcat 热部署时类总是加载失败?
  • SpringBoot 开启 DevTools 后内存暴涨、类冲突?
  • 使用 SPI 扩展接口,却加载不到自定义实现类?

所有这些问题背后,其实都是 类加载机制的问题。理解类是如何被加载、由谁加载、加载优先级如何决定,是中高级 Java 开发者迈向架构能力的必经之路。

二、JVM 中的类加载流程概览

Java 类从被引用到可以使用,需要经过以下 生命周期阶段:

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

你可以简单理解为:

JVM 读取 .class ➝ 结构校验 ➝ 为静态变量分配内存 ➝ 解析符号引用 ➝ 执行 方法

三、什么是双亲委派模型?

定义

BootstrapClassLoader(引导类加载器)↑
ExtensionClassLoader(扩展类加载器)↑
AppClassLoader(应用类加载器)↑
Custom ClassLoader(自定义类加载器)

加载逻辑伪代码

Class loadClass(String name) {// 已加载过,直接返回if (已加载类缓存中存在) return;// 委托父加载器加载if (parent != null) {try {return parent.loadClass(name);} catch (ClassNotFoundException e) {// 父类加载器找不到才尝试自己加载}}// 自己加载return findClass(name);
}

目的:

  • 防止类重复加载
  • 保证Java核心类的安全性和唯一性
  • 实现类的隔离性

四、演示:双亲委派如何避免核心类被污染?

我们试图编写一个名为 java.lang.String 的类并将其放入 classpath,结果会怎样?

package java.lang;
public class String {public String() {System.out.println("My Fake String Class");}
}

运行结果:

Error: Prohibited package name: java.lang

这是因为:

  • 核心类由 BootstrapClassLoader 先加载
  • 即使你的类也叫 java.lang.String,AppClassLoader 永远加载不到它

五、为什么需要打破双亲委派模型?

尽管双亲委派是安全可靠的,但在实际开发中,它也存在一些限制:
典型场景:

场景说明
热部署/类热替换无法重新加载类,只能加载一次(类缓存)
模块隔离(插件)插件类之间不能相互访问
SPI(服务发现机制)接口在父加载器,实现在子加载器,无法反射加载
动态编译/脚本执行引擎运行时生成类,不能由上层加载器访问

六、打破双亲委派模型的方式

方法一:重写 loadClass() 方法逻辑

@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {// 先尝试自己加载,不委托父类Class<?> c = findLoadedClass(name);if (c == null) {try {c = findClass(name); // 自己加载} catch (ClassNotFoundException e) {c = super.loadClass(name, resolve); // 找不到再委托父类}}return c;
}

注意:这样可能会破坏类的唯一性,导致 ClassCastException、类冲突等问题。

方法二:使用多个自定义类加载器做模块隔离

插件系统、脚本引擎常用此法:

ClassLoader pluginLoader1 = new MyClassLoader("pluginA/");
ClassLoader pluginLoader2 = new MyClassLoader("pluginB/");Class<?> clazz1 = pluginLoader1.loadClass("com.example.Plugin");
Class<?> clazz2 = pluginLoader2.loadClass("com.example.Plugin");System.out.println(clazz1 == clazz2); // false

不同插件类互相隔离,互不干扰。

七、双亲委派模型的常见陷阱

问题场景说明
类找不到(ClassNotFoundException)类存在但加载器层级错误
类转换异常(ClassCastException)类名相同但加载器不同,导致不兼容
内存泄漏类加载器无法被卸载,常见于容器或热部署场景

八、真实案例分析:Spring Boot DevTools

Spring Boot DevTools 实现类热替换的核心,就是通过 自定义类加载器打破双亲委派模型。

  • 应用类由自定义 RestartClassLoader 加载
  • 每次修改后重新加载类
  • 保证热更新不影响已运行类

九、类加载器在项目中的使用策略

场景建议做法
Web 容器部署避免将第三方 JAR 放入 shared/lib 中,易引发冲突
热部署系统使用隔离 ClassLoader + SPI
插件系统每个插件一个加载器,父加载器只负责接口
工具类封装使用当前线程类加载器(Thread.currentThread().getContextClassLoader())避免硬编码

十、总结

双亲委派模型是 Java 类加载机制的基础设计理念,保护了核心类的安全性与一致性。但在现代开发中,打破这个模型已经成为热部署、插件化架构的必要手段。

开发者要做到:

  • 明确使用哪些加载器
  • 避免无意义的类重复加载
  • 善用隔离加载器做模块隔离
  • 处理好类生命周期,防止泄漏

下一篇预告: 《JVM 调优实战入门:从 GC 日志分析到参数调优》手把手教你理解 GC 日志、如何识别性能瓶颈并合理配置 JVM 参数!

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

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

相关文章

Android SDK 开发中的 AAR 与 JAR 区别详解

在 Android SDK 开发中&#xff0c;构建项目时我们常常会看到生成两个不同的文件&#xff1a;一个是 build/outputs/aar/*.aar&#xff0c;另一个是 build/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar。很多初学者会疑惑&#xff1a;它们之间有什么区别&am…

服务器配置错误导致SSL/TLS出现安全漏洞,如何进行排查?

SSL/TLS 安全漏洞排查与修复指南 一、常见配置错误类型‌ 弱加密算法与密钥问题‌ 使用弱密码套件&#xff08;如DES、RC4&#xff09;或密钥长度不足&#xff08;如RSA密钥长度<2048位&#xff09;&#xff0c;导致加密强度不足。 密钥管理不当&#xff08;如私钥未加密存…

Day20打卡-奇异值SVD分解

今天学习非特征筛选的方法&#xff1a; 知识点回顾&#xff1a; 线性代数概念回顾&#xff08;可不掌握&#xff09;奇异值推导&#xff08;可不掌握&#xff09;奇异值的应用 特征降维&#xff1a;对高维数据减小计算量、可视化数据重构&#xff1a;比如重构信号、重构图像&am…

temu采购自养号全流程解析:从账号搭建到安全下单的技术闭环

temu 自养号采购下单技术是一个精细的过程&#xff0c;需要从多个方面进行考虑和操作&#xff0c;其核心在于通过技术手段模拟真实用户行为&#xff0c;构建独立、安全的账号环境以确保账号的安全性、真实性和采购下单的成功率。以下是对该技术的详细解析 1. 账号准备 手机号…

相机Camera日志分析之八:高通Camx HAL架构opencamera三级日志详解及关键字

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:相机Camera日志分析之七:高通Camx HAL架构opencamera二级日志详解及关键字 这一篇我们开始讲: 相机Camera日志分析之八:高通Camx HAL架构opencamera三级日志详解及关键字 目录 【关注我,后续持续…

自定义类型-结构体(二)

结构体内存对齐 偏移量 指的是结构体中某个成员相对于结构体起始地址的字节距离 第一个成员的起始位置为0&#xff0c;一个字节表示一个单位 这里的数字表示的是该成员地址与结构体首地址之间的值 对齐规则 1.结构体第一个成员的第一个字节的偏移量为0 2.其余成员变量要…

【免费工具】图吧工具箱2025.02正式版

DIY爱好者的必备工具 软件截图&#xff1a; —————【下 载 地 址】——————— 【本章单下载】&#xff1a;https://drive.uc.cn/s/f08aad37ddb14 【百款黑科技】&#xff1a;https://ucnygalh6wle.feishu.cn/wiki/HPQywvPc7iLZu1k0ODFcWMt2n0d?fromfrom_copylink …

DAX 权威指南1:DAX计算、表函数与计算上下文

参考《DAX 权威指南 第二版》 文章目录 二、DAX简介2.1 理解 DAX 计算2.2 计算列和度量值2.3 变量2.3.1 VAR简介2.3.2 VAR的特性 2.4 DAX 错误处理2.4.1 DAX 错误类型2.4.1.1 转换错误2.4.1.2 算术运算错误2.4.1.3 空值或 缺失值 2.4.2 使用IFERROR函数拦截错误2.4.2.1 安全地进…

【Linux系统】从零开始构建简易 Shell:从输入处理到命令执行的深度剖析

文章目录 前言一、打印命令行提示符代码功能概述 二、读取键盘输入的指令2.1 为什么不继续使用scanf()而换成了fgets()&#xff1f;2.2 调试输出的意义2.3 为什么需要去掉换行符&#xff1f; 三、指令切割补充知识&#xff1a; strtok 的函数原型 四、普通命令的执行代码功能概…

湖仓一体架构在金融典型数据分析场景中的实践

在数字经济与金融科技深度融合的今天&#xff0c;数据已成为金融机构的核心战略资产。然而&#xff0c;传统数据架构面临着三大困局&#xff0c;制约着金融机构数据价值的充分释放。 一、需求驱动更多银行数据分析场景 金融机构&#xff0c;特别是银行业&#xff0c;面临着双重…

基于Llama3的开发应用(一):Llama模型的简单部署

Llama模型的简单部署 0 前言1 环境准备1.1 硬件环境1.2 软件环境 2 Meta-Llama-3-8B-Instruct 模型简介2.1 Instruct含义2.2 模型下载 3 简单调用4 FastAPI 部署4.1 通过FastAPI简单部署4.2 测试 5 使用 streamlit 构建简易聊天界面6 总结 0 前言 本系列文章是基于Meta-Llama-…

模拟太阳系(C#编写的maui跨平台项目源码)

源码下载地址&#xff1a;https://download.csdn.net/download/wgxds/90789056 本资源为用C#编写的maui跨平台项目源码&#xff0c;使用Visual Studio 2022开发环境&#xff0c;基于.net8.0框架&#xff0c;生成的程序为“模拟太阳系运行”。经测试&#xff0c;生成的程序可运行…

基于人工智能的个性化 MySQL 学习路径推荐研究

基于人工智能的个性化 MySQL 学习路径推荐研究 摘要: 随着信息技术的飞速发展,数据库在各行业应用广泛,MySQL 作为主流数据库之一,学习需求庞大。然而,不同学习者在知识水平、学习进度和目标上存在差异,传统统一的学习路径难以满足个性化需求。本研究通过运用人工智能技…

OSPF综合应用

​ 要求&#xff1a; 1&#xff0c;R5为ISP&#xff0c;其上只能配置IP地址&#xff1b;R4作为企业边界路由器&#xff0c; 出口公网地址需要通过PPP协议获取&#xff0c;并进行chap认证 2&#xff0c;整个OSPF环境IP基于172.16.0.0/16划分&#xff1b; 3&#xff0c;所有设备…

中国古代史1

朝代歌 三皇五帝始&#xff0c;尧舜禹相传。 夏商与西周&#xff0c;东周分两段。 春秋和战国&#xff0c;一统秦两汉。 三分魏蜀吴&#xff0c;二晋前后延。 南北朝并立&#xff0c;隋唐五代传。 宋元明清后&#xff0c;皇朝至此完。 原始社会 元谋人&#xff0c;170万年前…

ensp的华为小实验

1.先进行子网划分 2.进行接口的IP地址配置和ospf的简易配置&#xff0c;先做到全网小通 3.进行ospf优化 对区域所有区域域间路由器进行一个汇总 对区域1进行优化 对区域2.3进行nssa设置 4.对ISP的路由进行协议配置 最后ping通5.5.5.5

华为OD机试真题——荒岛求生(2025A卷:200分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 200分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C、GO六种语言的最佳实现方式&#xff1b; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析&#xff1b; 本文收录于专栏&#xff1a;《2025华为OD真题目录…

IOC和Bean

IOC IOC将对象的创建&#xff0c;依赖关系的管理和生命周期的控制从应用程序代码中解耦出来了 IOC容器的依赖注入(DI) 在程序运行过程中动态的向某个对象中注入他所需要的其他对象 依赖注入是基于反射实现的 Spring IOC 容器使用的是Map&#xff08;concorrentMap&#xff…

vue3: pdf.js 2.16.105 using typescript

npm create vite vuepdfpreview //创建项目npm install vue-pdf-embed npm install vue3-pdfjs npm install pdfjs-dist2.16.105 <!--* |~~~~~~~|* | |* | |…

Java面试全栈解析:Spring Boot、Kafka与Redis实战揭秘

《Java面试全栈解析&#xff1a;Spring Boot、Kafka与Redis实战揭秘》 【面试现场】 面试官&#xff1a;&#xff08;推了推眼镜&#xff09;小张&#xff0c;你简历里提到用Spring Boot开发过微服务系统&#xff0c;能说说自动配置的实现原理吗&#xff1f; 程序员&#xff1…