JVM 类加载器有哪些?双亲委派机制的作用是什么?如何自定义类加载器?
类加载器分类
大家好,我是码哥,可以叫我靓仔,《Redis 高手心法》畅销书作者。

先回顾下,在 Java 中,类的初始化分为几个阶段: 加载、链接(包括验证、准备和解析)和 初始化。
而 类加载器(Class Loader)则是加载阶段中,负责将本地或网络中的指定类的二进制流,加载到 Java 虚拟机中的工具。
在进入正文前,介绍下我的《Java 面试高手心法 58 讲》专栏,帮助你在现在就业压力巨大的情况下比别人多一个杀手锏,拿下心仪 offer。内容涵盖 Java 基础、Java 高级进阶、Redis、MySQL、消息中间件、微服务架构设计等面试必考点、面试高频点。

丢掉你收藏的那些所谓的「面试宝典」,因为它们大多数深度不够,甚至内容还有错误,你只会看完就忘,还浪费时间。这也是为何每次面试你都回答不好,找不到好工作的原因。

引导类加载器 BootstrapClassLoader
引导类加载器 BootstrapClassLoader:引导类加载器是使用 C++ 语言实现的,嵌入在 JVM 中。用于加载 Java 中的核心类库的,不继承自 java.lang.ClassLoader,在 Java 程序中通常返回 null。
一般会加载 JAVA_HOME 目录下的 /jre/lib 文件夹下的 jar 和配置。
ClassLoader loader = String.class.getClassLoader();
System.out.println(loader); // 输出 null,因为 String 是由引导类加载器加载的 扩展类加载器 ExtClassLoader
扩展类加载器主要负责加载 Java 的扩展类库,一般会加载 JAVA_HOME 目录下的 /jre/lib/ext 文件夹下的 jar。
继承自 java.lang.ClassLoader,是用户可以访问的第一个类加载器。
ClassLoader extLoader = ClassLoader.getSystemClassLoader().getParent();
System.out.println(extLoader); // 输出 sun.misc.Launcher$ExtClassLoader 应用类加载器(Application ClassLoader)
应用类加载器是应用程序中默认的类加载器,可以加载 CLASSPATH 变量指定目录下的 jar,由 sun.misc.Launcher$AppClassLoader 实现。
并且一般情况下,我们编写的 Java 应用的类,都是使用该类加载器完成加载的。
ClassLoader appLoader = ClassLoader.getSystemClassLoader();
System.out.println(appLoader); // 输出 sun.misc.Launcher$AppClassLoader 类加载器抽象类 ClassLoader
在 Java 中存在一个类加载器抽象类 ClassLoader,大多数类加载器都是通过继承这个类来实现的类加载功能。以下是 ClassLoader 类的关键部分代码:
public abstract class ClassLoader {/** 类加载器的父加载器*/private final ClassLoader parent;/*** 根据类的全限定名加载类** @param name 类名称* @return 加载的Class对象* @throws ClassNotFoundException 没有发现指定类异常*/public Class<?> loadClass(String name) throws ClassNotFoundException {// 调用loadClass方法加载类,其中设置resolve=false,表示不立即解析类return loadClass(name, false);}/*** 根据类的全限定名加载类** @param name 类名称* @param resolve 是否解析这个类,true=解析,false=不解析* @return 加载的Class对象* @throws ClassNotFoundException 没有发现指定类异常*/protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {synchronized (getClassLoadingLock(name)) {// 检查类是否已经被加载Class<?> c = findLoadedClass(name);// 如果没有加载过if (c == null) {// 如果有父类加载器,则委托给父加载器去加载// 如果没有父类加载器,则判断 Bootstrap 类加载器是否加载过if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}// 如果父类加载器都加载失败,则当前类加载器尝试自行加载if (c == null) {c = findClass(name);}}// 据 resolve 参数决定是否解析类if (resolve) {resolveClass(c);}return c;}}/*** 查找并加载指定名称的类** @param name 类名称* @return Class对象* @throws ClassNotFoundException 没有发现指定类异常*/protected Class<?> findClass(String name) throws ClassNotFoundException {//1. 根据传入的类名,到在特定目录下去寻找类文件,把字节码文件读入内存// ...//2. 调用 defineClass 将字节数组转成 Class 对象return defineClass(buf, off, len);}/*** 将一个 byte[] 转换为 Class 类的实例** @param name 类名称,如果不知道此名称,则该参数为 null* @param b 组成类数据的字节数组* @param off 类数据的起始偏移量* @param len 类数据的长度* @return Class对象* @throws ClassFormatError 类格式化异常*/protected final Class<?> defineClass(byte[] b, int off, int len) throws ClassFormatError {...}} 类中定义的常用的类加载相关的方法:
| 方法名称 | 描述 |
|---|---|
| getParent() | 返回该类加载器的父类加载器 |
| loadClass(String name) | 加载指定名称的类,返回 java.lang.Class 实例 |
| findClass(String name) | 查找指定名称的类,返回 java.lang.Class 实例 |
| findLoadedClass(String name) | 查找已加载的指定名称的类,返回 java.lang.Class 实例 |
| defineClass(String name, byte[] b, int off, int len) | 将字节数组转换为一个 Java 类,返回 java.lang.Class 实例 |
| resolveClass(Class c) | 连接指定的 Java 类 |
双亲委派模型(Parent Delegation Model)
双亲委派模型 是类加载器的设计模式,其核心思想是:类加载请求由子类加载器向父类加载器逐层委派,直到引导类加载器。
如果父类加载器无法加载,子类加载器才会尝试加载。
如果子类加载器也无法加载该类,就会抛出一个 ClassNotFoundException 异常。
双亲委派机制的作用
我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的 String 类来动态替代 Java 核心 API 中定义的类型,这样会存在非常大的安全隐患。
而双亲委托的方式,就可以避免这种情况,因为 String 已经在启动时就被引导类加载器 (BootstrcpClassLoader) 加载,所以用户自定义的 ClassLoader 永远也无法加载一个用户自己自定义的 String 类,除非你改变 JDK 中 ClassLoader 搜索类的默认算法。
该机制的作用如下。
防止重复加载字节码文件: 将类加载请求先委托给父类,父类加载后子类就不会重复加载该类。所以,双亲委派机制可以防止对某个类重复加载;
防止核心字节码文件被篡改: 一般情况下引导类加载器会先加载 JVM 核心类库,然后其它加载器才会执行,如果其它加载器要加载一个被篡改的核心字节码文件,会将该文件委托给父类加载器,当委托到引导类加载器时,加载器已经加载过该类,就不会对该类进行重复加载。而且就算能被加载,那么加载它的肯定不是相同的类加载器 (不会是引导类加载器),Java 虚拟机中只认可核心类加载器加载的核心类库,所以,双亲委派机制可以防止核心字节码文件被篡改。
简化加载逻辑: 通过委派模式,每个类加载器只需要关注自己负责的那部分类加载逻辑,而不必关心其他类加载器的加载细节,简化了类加载器的实现,降低了系统的复杂度。
自定义类加载器
在某些场景下,标准的类加载器无法满足需求,例如:
热部署:在 Web 服务器中动态加载或更新类。
模块隔离:在同一个 JVM 中加载不同版本的类。
加密解密:加载经过加密的 Class 文件。
默认的类加载器只能加载指定目录下的 Jar 和 Class 文件。
如果需要加载指定位置的类文件并实现一些自定义逻辑,就需要自定义类加载器。
Chaya:如何实现自定义类加载器?
步骤:
继承
java.lang.ClassLoader类。重写
findClass()方法,通过字节流读取 Class 文件并转换为Class对象。
import java.io.*;public class MyClassLoader extends ClassLoader {@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {byte[] classData = loadClassData(name);if (classData == null) {throw new ClassNotFoundException();}return defineClass(name, classData, 0, classData.length);}private byte[] loadClassData(String name) {String fileName = name.replace('.', '/') + ".class";try (InputStream is = new FileInputStream(fileName);ByteArrayOutputStream baos = new ByteArrayOutputStream()) {int buffer;while ((buffer = is.read()) != -1) {baos.write(buffer);}return baos.toByteArray();} catch (IOException e) {e.printStackTrace();return null;}}
} 示例说明
findClass():从文件系统加载 Class 文件,并将其定义为Class对象。defineClass():将字节数组转换为 JVM 可执行的Class对象。
为了为保证类加载器都正确实现双亲委派机制,在开发自己的类加载器时,只需要重写 findClass() 方法即可。
当然,如果不想使用双亲委派机制时,就需要重写 loadClass() 方法。
打破双亲委派模型
有时为了实现特殊功能,我们需要打破双亲委派模型,例如:
热部署框架:Tomcat、Spring Boot 使用自定义类加载器加载和卸载 Web 应用。
SPI(Service Provider Interface)机制:JDBC 驱动等需要通过
线程上下文类加载器来加载用户实现的接口。
最后(Ending)
最后,顺带给大家介绍下,我的新书《Redis 高手心法》。

原价 100 元,现在只需要 50。
作者简介
《Redis 高手心法》 作者,InfoQ 签约作者、51CTO Top 红人。拥有 10 年互联网工作经验,作为后端架构师,擅长 Redis、Tomcat、Spring、Kafka、MySQL 技术,对分布式微服务架构有深入了解。

点击卡片,关注我,学技术
往期推荐
面试官拷打:Redis 高可用篇章中面试最常见的 6 个问题!
Redis 7.0 深度探秘:List 数据结构原理与实战指南
重生之从零设计 MySQL 架构
重生之MySQL SQL 执行的 7 大关键步骤,解锁新技能
相关文章:
JVM 类加载器有哪些?双亲委派机制的作用是什么?如何自定义类加载器?
类加载器分类 大家好,我是码哥,可以叫我靓仔,《Redis 高手心法》畅销书作者。 先回顾下,在 Java 中,类的初始化分为几个阶段: 加载、链接(包括验证、准备和解析)和 初始化。 而 类加载器&#x…...
从基态到激发态再到里德伯态的双光子激发过程
铯原子(Cs)从基态6S1/2到激发态6P3/2再到里德伯态44D5/2的双光子激发过程, 并通过数值计算和图形化展示来研究不同失谐条件下的拉比频率、AC Stark位移差以及散射概率的变化 结果显示,在给定的实验参数下,拉比频率较低…...
Clickhouse 外部存储引擎
文章目录 外部存储引擎分类MySQL引擎PostgreSQL引擎MongoDB引擎JDBC引擎ODBC引擎Kafka引擎RabbitMQ引擎File引擎URL引擎HDFS引擎 外部存储引擎分类 引擎类型描述特点MySQL从 MySQL 数据库中读取数据用于与 MySQL 数据库共享数据,支持读取 MySQL 表中的数据 支持 SQ…...
eclipse怎么配置jdk路径?
在Eclipse中配置JDK路径是一个简单的步骤,以下是配置JDK路径的步骤: 打开Eclipse:启动Eclipse IDE。 访问首选项: 在Eclipse的菜单栏中,选择 Window > Preferences(对于Mac OS X用户,选择 E…...
【前端】JavaScript 中的创建对象模式要点
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 💯前言💯对象属性值中的引号规则💯对象属性换行与尾随逗号的使用💯工厂模式:灵活高效的对象创建💯自定义构造函数:通过…...
GWAS分析先做后学
大家好,我是邓飞。 GWAS分析是生物信息和统计学的交叉学科,上可以学习编程,下可以学习统计。对于Linux系统,R语言,作图,统计学,机器学习等方向,都是一个极好的入门项目。生物信息如…...
【系统设计】高可用之缓存基础
缓存的缘起 使用缓存的主要原因包括提高系统性能、降低数据库负载、提升用户体验和保证系统可用性。 在计算机体系结构中,由于处理器和存储器的处理时间不匹配,在处理器和一个较大较慢的设备之间插入一个更小更快的存储设备(如高速缓存&a…...
《Java核心技术I》volatile字段
volatile字段 有多处理器的计算机能够暂时在寄存器或本地内存缓存中保存内存值,其结果是,运行在不同处理器上的线程可能看到同一个内存位置上有不同的值。编译器可以改变指令执行的顺序以使吞吐量更大化,编译器不会选择可能改变代码语义的顺…...
2024运维故障记 | 12/2 网易云音乐崩了
#运维故障记# 前两天看到网易云音乐崩了的新闻,回想了一下,今年从网易云音乐到支付宝、还有微软,近期就发生了好几起运维届的故障。 今年来不及计数了,先做个记录。 明年看看运维届的大故障会发生多少,什么原因&…...
架构设计读后——微服务
1 微服务历史 2005年:Dr. Peter Rodgers提出"Micro-Web-Services"概念2011年:一个软件架构工作组使用"microservice"来描述一中架构模式2012年;这个工作组正式使用"microservice"来代表这个架构2012年&#x…...
软考高级架构-9.4.4-双机热备技术 与 服务器集群技术
一、双机热备 1、特点: 软硬件结合:系统由两台服务器(主机和备机)、一个共享存储(通常为磁盘阵列柜)、以及双机热备软件(提供心跳检测、故障转移和资源管理功能的核心软件)组成。 …...
聊聊前端工程化
深度解析前端工程化 近年来,随着前端技术的快速迭代和项目复杂度的增加,前端开发已经从简单的页面搭建演变为专业的工程化体系。前端工程化通过工具链、标准化和流程化手段,不仅提高了开发效率,也大幅提升了项目的可维护性和协…...
“放弃Redis Desktop Manager使用Redis Insight”:日常使用教程(Redis可视化工具)
文章目录 更新Redis Insight连接页面基础解释自动更新key汉化暂时没有找到方法, Redis Desktop Manager在连接上右键在数据库上右键在key上右键1、添加连接2、key过期时间 参考文章 更新 (TωT)ノ~~~ βyё βyё~ 现在在维护另一…...
mmdection配置-yolo转coco
基础配置看我的mmsegmentation。 也可以参考b站 :https://www.bilibili.com/video/BV1xA4m1c7H8/?vd_source701421543dabde010814d3f9ea6917f6#reply248829735200 这里面最大的坑就是配置coco数据集。我一般是用yolo,这个yolo转coco格式很难搞定&#…...
聚合支付系统/官方个人免签系统/三方支付系统稳定安全高并发 附教程
聚合支付系统/官方个人免签系统/三方支付系统稳定安全高并发 附教程 系统采用FastAdmin框架独立全新开发,安全稳定,系统支持代理、商户、码商等业务逻辑。 针对最近一些JD,TB等业务定制,子账号业务逻辑API 非常详细,方便内置…...
力扣67. 二进制求和
给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。 示例 1: 输入:a "11", b "1" 输出:"100" 示例 2: 输入:a "1010", b "1011" 输出&#…...
网络安全中的 SOC 是什么?
当今世界,网络威胁日益增多,确保网络安全已成为各种规模企业的首要任务。网络安全讨论中经常出现的一个术语是 SOC,即安全运营中心的缩写。但网络安全中的 SOC 是什么呢? SOC在防御网络威胁、管理安全事件和全天候监控系统方面发…...
16、鸿蒙学习——Visibility与(if...else)该如何选择
在鸿蒙中我们如果要控制一个组件的显示与隐藏可以设置组件的Visibility属性,也可使用(if...else)条件控制,具体我们该选择哪个?二者有什么区别呢? 1、Visibility 名称描述Hidden隐藏,但参与布局…...
PH热榜 | 2024-12-05
1. Oopsie 标语:用AI和会话回放调试Flutter和React Native应用 介绍:Zipy推出的Oopsie是一款你唯一需要的AI赋能移动端调试工具,它能提供▶️会话回放、🤖错误监控、💡AI生成的概要分析,以及🔥…...
Qt Chart 模块化封装曲线图
一 版本说明 二 完成示例 此文章包含:曲线轴设置,曲线切换,单条曲线显示,坐标轴。。。 三 曲线图UI创建 在UI界面拖放一个QWidget,然后在 Widget里面放一个 graphicsView 四 代码介绍 1 头文件 #include <QString> #include <QTimer> #include <QMessa…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...
6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙
Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...
2025-05-08-deepseek本地化部署
title: 2025-05-08-deepseek 本地化部署 tags: 深度学习 程序开发 2025-05-08-deepseek 本地化部署 参考博客 本地部署 DeepSeek:小白也能轻松搞定! 如何给本地部署的 DeepSeek 投喂数据,让他更懂你 [实验目的]:理解系统架构与原…...
