学类加载器的时候,我被“谁加载谁“绕了好几天

发布时间:2026/8/26 23:05:12

学类加载器的时候,我被“谁加载谁“绕了好几天
刚开始学 JVM 类加载机制的时候我最头疼的不是加载过程分几步而是这几层类加载器到底谁是谁的爸爸。启动类加载器、扩展类加载器、应用类加载器、自定义类加载器……名字一堆关系图一画就乱。而且学完之后我一度觉得这东西离业务代码很远平时写 Spring Boot 又用不到。后来踩了几个坑才明白类加载器的设计直接关系到 Java 的安全性和动态性不搞懂不行。类加载器到底是什么为什么需要分层类加载器的任务很简单把一个类的二进制字节码读进 JVM转换成java.lang.Class对象。但问题在于Java 程序运行的时候会从很多不同的地方加载类。比如java.lang.String是从 JDK 核心库来的你项目里引的第三方 jar 是从 Maven 仓库来的你自己写的类在 target/classes 里。JVM 需要区分这些类的来源不能让一个来自不可信来源的类冒充核心类。这就是分层设计的出发点。你可以把类加载器想象成一层一层的安检。最内层由 JVM 自己把守只放行最核心的类。越往外信任度越低但灵活性越高。四层类加载器每层的职责不一样1. 启动类加载器Bootstrap Class LoaderJVM 自己管的这是所有类加载器里地位最高的一个。它负责加载 Java 最核心的类库。它加载什么在 Java 8 及以前它加载的是jre/lib/rt.jar。rt.jar里装的是java.lang.*、java.util.*、java.io.*这些你每天都在用的类。从 Java 9 开始rt.jar被移除了核心类库以模块化的形式存放在$JAVA_HOME/lib/modules里比如java.base模块。它特殊在哪启动类加载器不是用 Java 写的而是 C 实现的是 JVM 的一部分。所以在 Java 代码里你拿不到它的对象调用getClassLoader()返回的是null。我第一次看到这个设计的时候有点懵返回 null 不会空指针吗后来才知道这算是 JVM 约定好的信号看到 null 就知道这个类是 Bootstrap ClassLoader 加载的不是 Bug。2. 平台类加载器Platform / Extension Class Loader中间层这一层的名字在 Java 8 和 Java 9 不一样。Java 8 及以前扩展类加载器Extension Class Loader它负责加载jre/lib/ext目录下的扩展 jar 包。你也可以通过java.ext.dirs系统属性指定额外的扩展目录。这个设计本意是让 JDK 可以在不修改核心库的前提下扩展功能。Java 9 及以后平台类加载器Platform Class LoaderJava 9 模块化之后jre/lib/ext目录和java.ext.dirs属性都被移除了。新的平台类加载器负责加载 JDK 中除核心模块之外的那些平台模块比如java.sql、java.xml这些。一个容易混淆的点在 Java 层面这个加载器的parent字段是null。但它的委派逻辑仍然会把请求先交给 Bootstrap ClassLoader。这里的 “parent null” 只是表示在 Java 层面没有一个对应的 ClassLoader 对象作为父加载器不表示它不向上委派。我当时被这个搞混过看到 parent 是 null 以为它就是顶层了结果发现它还会向上抛给启动类加载器。3. 应用程序类加载器Application Class Loader你用得最多的这个加载器负责加载你的项目里写的类和引用的第三方 jar 包。具体来说就是 ClassPath类路径和模块路径上的所有类。你可以通过ClassLoader.getSystemClassLoader()拿到它。在 Java 9 里它的父加载器是 Platform Class Loader在 Java 8 里是 Extension Class Loader。平时写代码的时候你几乎感觉不到它的存在但你写的每个类的加载都是经过它的。4. 自定义类加载器Custom Class Loader给你自己玩的如果你觉得上面三层的加载方式满足不了你的需求你可以自己写一个 ClassLoader继承java.lang.ClassLoader就行。什么时候需要自己写类文件不在文件系统上而是从网络上下载类文件被加密了需要在加载时解密类文件存在数据库里你想对加载的字节码做增强比如一些 APM 工具就是这么做的我刚开始觉得自定义类加载器是八股文里才会出现的东西。后来用了一次 Spring Boot 的 DevTools发现它就是用不同的类加载器来隔离重新加载的类和原有的类才知道这东西在实际项目里真的在用。层级关系和双亲委派模型四层加载器的层级关系是这样的Bootstrap ClassLoader顶层C 实现 ↑ 委派 Platform / Extension ClassLoader ↑ 委派 Application ClassLoader ↑ 委派 Custom ClassLoader开发者自定义注意箭头的方向是向上委派不是向下查找。双亲委派到底是怎么工作的当一个类加载器收到加载一个类的请求时它不会自己先去尝试加载而是先把请求交给它的父加载器。父加载器又交给它的父加载器……一直交到最顶层的启动类加载器。启动类加载器尝试加载如果加载不到它返回我干不了然后下一级加载器再尝试。用一个具体的例子走一遍假设你要加载com.example.MyService。应用类加载器收到了请求。应用类加载器说“我先问问我爸爸能不能加载。”它把请求交给了平台类加载器Java 9 的话。平台类加载器也说“我再问问我爸爸。”平台类加载器把请求交给 Bootstrap ClassLoader。Bootstrap ClassLoader 尝试加载com.example.MyService。它只负责核心类库找不到这个类。Bootstrap ClassLoader 返回我找不到。平台类加载器自己尝试加载。它只负责平台模块也找不到。平台类加载器返回我也找不到。应用类加载器终于自己出手了。它在自己负责的 ClassPath 上找到了com.example.MyService加载成功。这个流程走下来你会发现问题每一层都要先问爸爸层层向上再层层向下。这不是很慢吗为什么非要这么设计双亲委派看起来绕但它的核心目的只有一个保证核心类的唯一性。如果不用双亲委派你可以在自己的代码里写一个java.lang.String然后用自己的类加载器加载。JVM 就分不清哪个是真正的 JDK 核心类哪个是你自己写的。这种混乱会带来安全性问题想象一下有人写了一个假的javax.crypto.Cipher在里面做手脚。双亲委派的解决方案是不管谁要加载java.lang.String请求都会一路向上传到 Bootstrap ClassLoader。Bootstrap ClassLoader 加载了真正的java.lang.String然后返回给下层。下层就不会再尝试用自己的版本了。这样就保证了全 JVM 范围内java.lang.String只有一份。我第一次理解这个设计意图的时候觉得还是挺巧妙的。用了一个简单的向上问的规则就解决了类重复和类安全两个问题。代价只是在加载过程中多走几层委派而类加载本身是低频操作这点性能损失可以忽略。双亲委派不是万能的但这个模型也有解决不了的问题。Java SPIService Provider Interface就是一个典型例子。SPI 的机制是定义一个接口比如java.sql.Driver接口在核心库里但实现类比如 MySQL 的驱动在第三方 jar 里。Bootstrap ClassLoader 加载了java.sql.Driver但当它尝试加载实现类的时候它找不到因为它根本不负责 ClassPath。Java 的解决方案是Thread.currentThread().getContextClassLoader()拿到当前线程的上下文类加载器通常是应用类加载器让爸爸用儿子的加载器去加载类。这就是所谓的打破双亲委派。Tomcat 这样的 Web 容器也要打破双亲委派。每个 Web 应用需要独立加载自己的类互不干扰。你部署了两个 war 包里面都有同名的类不能互相覆盖。Tomcat 的做法是给每个 Web 应用创建独立的类加载器优先自己加载加载不到才交给父加载器跟双亲委派的方向刚好反过来。不同版本之间的变化学习类加载器的时候Java 8 和 Java 9 的差异让我多花了不少时间。因为网上的很多博客还在讲 Java 8 的体系而我现在用的已经是 Java 17 了。项目Java 8 及以前Java 9 及以后核心类库jre/lib/rt.jar$JAVA_HOME/lib/modules模块化运行时镜像第二层加载器Extension Class LoaderPlatform Class Loader扩展目录jre/lib/ext已移除系统属性java.ext.dirs已移除最核心的变化是 Java 9 的模块化系统Project Jigsaw。它不仅改了类加载器的名字还改了类库的存储方式和访问权限。用旧的博客文章学新版本的 JVM确实需要小心配对版本。学完之后我觉得需要记住的把类加载器的体系过了一遍之后有几个体会比较深1. 分层是手段安全才是目的。类加载器的分层不是为了好看而是为了让核心类不被冒充。双亲委派用极简的向上问规则实现了这一点。2. null 不等于没有。Bootstrap ClassLoader 在 Java 代码里用 null 表示但它是真实存在的。在 Java 里看到getClassLoader()返回 null就知道这类的来头最大。3. 打破双亲委派不是 bug是 feature。SPI、Web 容器、热部署工具它们需要打破双亲委派不是因为模型设计得不好而是因为有些场景天然就不符合向上问的逻辑。框架需要自己决定怎么加载。4. 版本很重要。Java 9 改了类加载器的命名和结构连rt.jar都没了。如果还在看 Java 8 的博客学现在的 JVM有些地方需要对得上号。如果你也在学类加载器建议先动手写一个简单的自定义 ClassLoader。不用复杂覆写findClass()方法从文件系统或者网络加载一个类就行。做一遍之后你对委派和加载的理解会比只看文章深很多。

相关新闻

告别内卷式养生,女性的温柔轻养之道

告别内卷式养生,女性的温柔轻养之道

2026/8/26 3:36:27

一、饮食轻养:少负担、重通透,拒绝盲目进补很多中年女性养生容易走入误区:过度吃滋补品、重油重补,反而加重身体代谢负担,出现上火、积食、发胖等问题。轻养生的核心饮食原则,是清淡均衡、七分饱腹、通透养…

[Android] Namida-高颜值音乐播放-不输椒盐

[Android] Namida-高颜值音乐播放-不输椒盐

2026/8/25 3:39:03

[Android] Namida-高颜值音乐播放-不输椒盐 链接:https://pan.xunlei.com/s/VOwe_P9-pRUAX3pVvJi2zMuuA1?pwdzrka# 强大的媒体库管理,YouTube 集成:支持音视频播放、缓存与离线下载,内置SponsorBlock 跳过赞助片段、Return Y…

2026年最新好用英语单词软件推荐 帮你稳步提升日常英语水平

2026年最新好用英语单词软件推荐 帮你稳步提升日常英语水平

2026/8/26 15:21:12

很多人想提升日常英语水平,但始终卡在单词积累这关,要么背了就忘,要么学了不会用。结合我5年做英语学习内容的实测经验,今天拆解单词学习的核心行业痛点,以及AI技术落地的可行解决方案,附中立的软件选型建议…

Fiddler弱网测试实战:模拟真实网络环境,提升应用健壮性

Fiddler弱网测试实战:模拟真实网络环境,提升应用健壮性

2026/8/26 22:56:54

1. 项目概述:为什么我们需要模拟弱网环境? 在移动应用和Web服务开发测试的日常工作中,我们常常会陷入一个“温室”误区:所有测试都在公司高速、稳定的Wi-Fi或千兆有线网络下进行。测试工程师点击按钮,页面瞬间加载&…

Mac软件“已损坏”提示的根源与解决方案:从Gatekeeper到终端命令

Mac软件“已损坏”提示的根源与解决方案:从Gatekeeper到终端命令

2026/8/26 22:56:54

1. 问题根源:为什么Mac总说我的软件“已损坏”?如果你是从Windows或Linux转投Mac阵营的用户,第一次遇到“无法打开‘XXX’,因为它来自身份不明的开发者”或者“XXX已损坏,无法打开。您应该将它移到废纸篓”这类弹窗时&…

腾讯云Token Plan个人版套餐选择指南:从AI编程到API调用的成本优化策略

腾讯云Token Plan个人版套餐选择指南:从AI编程到API调用的成本优化策略

2026/8/26 22:56:54

1. 项目概述:Token Plan个人版套餐选择困境 最近在AI编程和API调用圈子里,腾讯云的Token Plan个人版套餐讨论热度很高。很多开发者,无论是独立开发者、学生,还是小团队的成员,都在纠结同一个问题:面对39元、…

Jetson Orin升级JetPack 7.2:解锁DeepStream多路视频分析性能瓶颈

Jetson Orin升级JetPack 7.2:解锁DeepStream多路视频分析性能瓶颈

2026/8/26 22:56:54

1. 项目概述:一次关键的固件与软件栈升级如果你正在使用NVIDIA Jetson Orin系列平台进行DeepStream相关的开发,无论是做多路视频分析、智能边缘计算盒子,还是机器人视觉中枢,那么最近NVIDIA官方发布的Jetpack 7.2绝对是一个值得你…

WorkBuddy:企业AI原生应用平台,6-9个月实现50%-80%效率跃迁

WorkBuddy:企业AI原生应用平台,6-9个月实现50%-80%效率跃迁

2026/8/26 22:56:54

1. 项目概述:当AI助手成为你的“工作伙伴”最近和几个不同行业的朋友聊天,发现一个挺有意思的现象:大家嘴上都在谈“AI转型”,但真把AI用起来、用出效果的团队,其实没想象中那么多。很多公司要么是采购了昂贵的SaaS服务…

LibreOffice命令行实现Word转PDF:服务器端批量转换与工程化实践

LibreOffice命令行实现Word转PDF:服务器端批量转换与工程化实践

2026/8/26 22:46:53

1. 从“另存为”到“工程化”:为什么Word转PDF远不止点个按钮 如果你在办公室里问一个同事怎么把Word转成PDF,十有八九他会告诉你:“简单啊,Word里直接另存为不就行了?” 这话没错,对于偶尔处理一两份文档的…

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

2026/8/26 1:50:39

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

2026/8/26 1:49:16

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

2026/8/26 17:50:58

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

Python random 模块常用函数详解:从入门到实战

Python random 模块常用函数详解:从入门到实战

2026/8/26 0:05:45

目录 1. 引言2. 准备工作3. 基础随机函数4. 序列相关函数5. 随机种子与复现6. 实战案例7. 注意事项8. 常见问题与排查9. 总结 1. 引言 摘要: 本文系统介绍 Python 标准库 random 模块中最常用的随机数生成函数。内容涵盖基础随机函数(random()、unifor…

Hermes接入团队协作后,我推翻了三个效率假设

Hermes接入团队协作后,我推翻了三个效率假设

2026/8/26 0:05:45

聊《Hermes真能提效吗?先看流程里最慢的那一步》之前,先说一句实在的:别急着背概念,先看它在真实项目里到底解决什么问题。摘要团队把 Hermes 接进项目三个月后,交付速度没有提升反而慢了。复盘后发现,最先…

免费AI大模型调教指南:打造专属网文写作助手

免费AI大模型调教指南:打造专属网文写作助手

2026/8/26 0:05:45

1. 先搞清楚“AI小说扩展模式”到底能帮你做什么如果你是一个刚开始写网文、或者卡在L3级别以下的作者,最头疼的可能是情节推进不下去、人物对话干瘪,或者世界观设定不够丰满。自己对着空白文档硬憋,效率很低。这时候,一个能理解你…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/22 2:02:26

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/26 18:07:30

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/26 17:57:52

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…