【JVM】已验鼎真,鉴定为:妈妈加载的(双亲委派模型)

news2024/11/20 0:49:50

【JVM】已验鼎真,鉴定为:妈妈加载的(双亲委派模型)

在Java的世界中,类加载器(ClassLoader)是Java虚拟机(JVM)用来动态加载类的基础组件。双亲委派模型(Parent Delegation Model)是Java类加载机制中一个至关重要的设计,它确保Java类加载过程的安全性和稳定性。本文将简单介绍JVM中的类加载器机制及其双亲委派模型。

首先我们来看看类加载器。

一、类加载器概述

Java中的类加载器主要有以下几种:

  1. Bootstrap ClassLoader(引导类加载器)
    • 由C++实现,是JVM自身的一部分。
    • 负责加载Java的核心类库,例如rt.jar中的类。
  2. Extension ClassLoader(扩展类加载器)
    • sun.misc.Launcher$ExtClassLoader实现。
    • 负责加载Java扩展库(JDK扩展目录lib/ext中的JAR包)。
  3. 应用程序类加载器(Application Class Loader)
    • sun.misc.Launcher$AppClassLoader实现。
    • 负责加载应用程序的类路径(classpath)上的类。
  4. User-defined ClassLoader(用户自定义类加载器)
    • 通过继承java.lang.ClassLoader可以实现自定义类加载器。
    • 用于加载特定需求的类,例如网络类加载器、数据库类加载器等。

image-20240605215628999

二、双亲委派模型

双亲委派模型,准确来说,即当一个类加载器收到一个类的加载请求时,首先不会自己尝试去加载它,而是把这一请求委派给父类加载器去完成,这样层层委派,因此所有的加载请求都最终会被传送到顶层的启动类加载器中。

只有当父类加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。

  1. 检查缓存:类加载器首先检查自己是否已经加载过该类,如果加载过则直接返回。
  2. 委派父类加载器:如果自己没有加载过,则将加载请求委派给父类加载器。
  3. 递归委派:父类加载器同样遵循上述步骤,递归检查其父类加载器,直到顶层的Bootstrap ClassLoader(启动类加载器)。
  4. 加载类:如果顶层的类加载器无法加载该类,则依次往下返回,由各级子类加载器尝试加载该类。
  5. 缓存加载结果:成功加载类后,将该类缓存以便下次直接使用。

双亲委派模型的优点

  1. 安全性:通过双亲委派机制,可以防止核心类库被篡改。例如,Java核心类库中的java.lang.String类只有由Bootstrap ClassLoader加载,防止应用程序自定义一个java.lang.String类来替换。
  2. 避免重复加载:确保同一个类只被加载一次。即使在不同的类加载器中,只要遵循双亲委派机制,类加载器会避免重复加载同一个类。
  3. 模块化:使得类加载器可以在一个隔离的环境中加载类,适应不同的需求,例如应用服务器中不同应用的隔离运行。

双亲委派模型的缺点

  1. 灵活性不足:在某些情况下,双亲委派模型的严格父子关系限制了类加载器的灵活性。例如,开发人员可能希望在应用程序中加载一个与系统类库版本不同的库。
  2. 调试困难:由于类加载过程涉及多个类加载器的协同工作,调试类加载问题时可能比较复杂,尤其是在遇到类加载冲突或类版本不一致的情况。

三、如何打破双亲委派模型

正常加载类的顺序,是用户自定义类加载器 -> 应用程序类加载器 -> 扩展类加载器 -> 引导类加载器,如果不遵循这个顺序,就是在打破双亲委派机制。

而双亲委派过程都是在loadClass方法中实现的,如果想要破坏这种机制,那么就自定义一个类加载器,重写其中的loadClass方法,使其不进行双亲委派即可。

例如:

public class CustomClassLoader extends ClassLoader {
    
    public CustomClassLoader(ClassLoader parent) {
        super(parent);
    }
    
    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        // 不委派给父类加载器,直接尝试加载目标类
        try {
            // 尝试从当前类加载器的资源路径加载类
            byte[] classData = loadClassData(name);
            if (classData != null) {
                return defineClass(name, classData, 0, classData.length);
            }
        } catch (Exception e) {
            // 忽略加载异常
        }
        
        // 如果当前类加载器无法加载,委派给父类加载器
        return super.loadClass(name);
    }
    
    private byte[] loadClassData(String name) {
        // 从文件或其他资源中读取类字节码的逻辑
        // ...
        return null; // 实际实现时应返回有效的字节码数据
    }
}

四、双亲委派模型的示例

以Tomcat为例,Apache Tomcat是一个广泛使用的Java Web服务器,一个web容器可能需要部署多个应用程序,不同的应用程序可能会依赖同一个第三方库的不同版本,但是不同版本的库中某一个类的全路径名可能是一样的。

它提供了一种机制来打破双亲委派模型,以支持不同Web应用之间的类隔离。Tomcat中,每个Web应用都有自己的类加载器,并且Tomcat的类加载机制允许在特定情况下打破双亲委派模型。

Tomcat的类加载器架构如下:

  1. Bootstrap ClassLoader:加载Java核心类库。
  2. System ClassLoader:加载Tomcat自身的类库。
  3. Common ClassLoader:加载Tomcat的共享类库。
  4. Webapp ClassLoader:每个Web应用有独立的类加载器,用于加载该应用的类和库。

如果采用默认的双亲委派类加载机制,无法加载多个相同的类。

所以,Tomcat破坏双亲委派原则,提供隔离的机制,为每个web容器单独提供一个WebAppClassLoader加载器,每个应用都有自己的类加载器WebAppClassLoader,该加载器重写了loadClass方法,会优先加载当前应用下的类,加载不到时再交给WebAppClassLoader的父加载器SharedClassLoader去加载。

打破双亲委派模型是一种特殊的需求,通常用于解决特定的类加载冲突或版本兼容问题。在Tomcat等应用服务器中,通过自定义类加载器和配置,可以实现对类加载过程的精细控制。理解和灵活应用类加载机制,可以帮助开发人员更好地管理和优化Java应用程序的运行环境。

结语

双亲委派机制属于类加载机制的后续,本来应该很早就发出来力,因为内容不多,但是因为笔者很懒所以拖到现在啦~属于是终于填坑了属于是。

参考文献

深入浅出Java类加载机制(双亲委派模型)与自定义类加载器实践_java类的装载机制-CSDN博客

java—双亲委派模型_java中双亲委派模型-CSDN博客

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

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

相关文章

java多线程原理

1.线程创建与启动&#xff1a;通过继承Thread类或实现Runnable接口创建线程&#xff0c;并调用start()方法启动线程。 1.线程状态&#xff1a;线程在其生命周期中有多种状态&#xff0c;包括新建、运行、阻塞、死亡等。了解这些状态以及如何在它们之间转换对于管理线程至关重要…

人工智能在病理组学中的发展历程概述|24年6月·顶刊速递·06-04

小罗碎碎念 今天分享的七篇文章&#xff0c;主题非常明确——人工智能在数字病理领域的发展情况。 前六篇文献选自Nature&#xff0c;第七篇文献选自Cell&#xff0c;文献的发表时间从2019年跨越至2024年&#xff0c;囊括了AI在数字病理领域的里程碑式进展。 这期推文值得所有…

输出流--6.6

代码以及解释&#xff1a; package java2;import java.io.File; import java.io.FileWriter; import java.io.IOException;public class Test02 {public static void main(String[] args) throws IOException {String str "flag{hello_ctf}";//1.封装File fnew Fil…

代码解读 | Hybrid Transformers for Music Source Separation[02]

一、背景 今天对Hybrid Transformer Demucs代码进行解读&#xff0c;目标&#xff1a;对图c中各个模块对应的代码进行解读&#xff08;时域编码、频域编码、时域解码、频域解码、Cross-Domain Transformer Encoder模块、STFT模块、ISTFT模块&#xff09;。解读的代码是开源工程…

深入解析ArrayList是如何实现自动扩容的?【源码深度解析】

一 、分析ArrayList扩容源码 通过在 &#xff08;JDK 6 及更低版本中&#xff09;API我们知道&#xff0c;调用无参构造创建的ArrayList集合&#xff0c;初始容量为10 接下来我们深入源码&#xff0c;探究当时作者是怎么构思的 借助Debug工具&#xff0c;一步一步进入 上图看到…

list的简单模拟实现

文章目录 目录 文章目录 前言 一、使用list时的注意事项 1.list不支持std库中的sort排序 2.去重操作 3.splice拼接 二、list的接口实现 1.源码中的节点 2.源码中的构造函数 3.哨兵位头节点 4.尾插和头插 5.迭代器* 5.1 迭代器中的operator和-- 5.2其他迭代器中的接口 5.3迭代器…

web学习笔记(六十二)

目录 1.键盘事件 2.KeepAlive 3.组件传值 3.1 兄弟组件传值 3.2 组件树传值 3.3 发布订阅者传值 1.键盘事件 keydown表示键盘事件&#xff0c;在不加修饰符的情况下&#xff0c;点击键盘上的任意位置都可以触发键盘事件&#xff0c; <template><div><!--…

LeetCode-82. 删除排序链表中的重复元素 II【链表 双指针】

LeetCode-82. 删除排序链表中的重复元素 II【链表 双指针】 题目描述&#xff1a;解题思路一&#xff1a;用一个cur即可实现去重cur.next cur.next.next背诵版&#xff1a;解题思路三&#xff1a;0 题目描述&#xff1a; 给定一个已排序的链表的头 head &#xff0c; 删除原始…

HTML静态网页成品作业(HTML+CSS)—— 父亲节节日介绍网页(4个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有4个页面。 二、作品演示 三、代…

【学习心得】算法刷题心得分享

一、为什么要刷题&#xff1f; 提升编程能力&#xff0c;强化对数据结构的理解&#xff0c;熟练掌握常用的算法等为竞赛、考试做准备找实习、找工作需要&#xff08;上机考试面试手撕代码&#xff09;提升自信心&#xff0c;放松一下 二、刷题前应该有哪些知识储备&#xff1f;…

java代码审计之fastjson反序列化漏洞

fastjson反序列化漏洞分析 Fastjson 是一个 Java 库&#xff0c;可以将 Java 对象转换为 JSON 格式&#xff0c;当然它也可以将 JSON 字符串转换为 Java 对象。Fastjson 可以操作任何 Java 对象&#xff0c;即使是一些预先存在的没有源码的对象。该产品主要提供了两个接口&…

官宣!2024 MongoDB Developer Day来了!北上深三场等你集结!

北上深开发者 专为你们打造的 MongoDB Developer Day 来了&#xff01; 动手实操工作坊➕模型设计优化专场 学习 NoSQL 数据建模的最佳实践 深入探索 MongoDB 的各种可能性 和开发者同行和 MongoDB 技术专家 一起度过充实的一天&#xff01; 北京&#xff08;6/22&…

UMLChina为什么叒要翻译《分析模式》?

UMLChina受机械工业出版社委托&#xff0c;重新翻译《分析模式》。 Martin Fowler的“Analysis Patterns&#xff0c;Reusable Object Models”&#xff0c;原书出版于1997年&#xff0c;至今为止未出第2版。 2004年&#xff0c;机械工业出版社出版该书中译本《分析模式》。 …

Django render()函数页面渲染

1&#xff0c; render() 函数 在Django框架中&#xff0c;render() 函数是一个非常有用的快捷方式&#xff0c;用于从视图函数返回一个完整的HTTP响应。它负责将给定的模板与上下文数据结合&#xff0c;渲染出最终的HTML页面&#xff0c;并返回一个HttpResponse对象。 from d…

千锋教育大优惠

IT全学科自学至尊卡&#xff08;3年卡&#xff09; Linux云计算运维、Python全栈、数据分析、人工智能、Java、大前端、网络安全、物联网、全媒体、影视剪辑等14大主流方向&#xff0c;300精品视频课程免费学。课程持续更新&#xff0c;电脑端手机APP小程序多平台无忧畅学&…

JavaWeb1 Json+BOM+DOM+事件监听

JS对象-Json //Json 字符串转JS对象 var jsObject Json.parse(userStr); //JS对象转JSON字符串 var jsonStr JSON.stringify(jsObject);JS对象-BOM BOM是浏览器对象模型&#xff0c;允许JS与浏览器对话 它包括5个对象&#xff1a;window、document、navigator、screen、hi…

【人工智能】第一部分:ChatGPT的基本概念和技术背景

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

王道408数据结构CH3_栈、队列

概述 3.栈、队列和数组 3.1 栈 3.1.1 基本操作 3.1.2 顺序栈 #define Maxsize 50typedef struct{ElemType data[Maxsize];int top; }SqStack;3.1.3 链式栈 typedef struct LinkNode{ElemType data;struct LinkNode *next; }*LiStack;3.2 队列 3.2.1 基本操作 3.2.2 顺序存储…

C++ Primer 总结索引 | 第十五章:面向对象程序设计

继承和动态绑定 对程序的编写 有两方面的影响&#xff1a;一是 我们可以更容易地定义与其他类相似 但不完全相同的新类&#xff1b;二是 在使用这些彼此相似的类编写程序时&#xff0c;我们可以在一定程度上 忽略掉它们的区别 在很多程序中都存在着一些相互关联 但是有细微差别…

用幻灯片讲解C++手动内存管理

用幻灯片讲解C手动内存管理 1.栈内存的基本元素 2.栈内存的聚合对象 3.手动分配内存和释放内存 注意&#xff1a;手动分配内存&#xff0c;指的是在堆内存中。 除非实现自己的数据结构&#xff0c;否则永远不要手动分配内存! 即使这样&#xff0c;您也应该通过std::allocator…