【JVM】Java类加载器 和 双亲委派机制

news2024/11/26 17:02:03
1、java类加载器的分类

JDK8及之前

  • 启动类加载器,BootStrap Class Loader,加载核心类,加载jre/lib目录下的类,C++实现的
  • 拓展类加载器, Extension Class Loader,加载java拓展类库,jre/lib/ext目录下,比如javax,java.util包等
  • 应用程序类加载器,Application Class Loader, 也成系统类加载器,负责加载应用程序类,classpath下的类文件,maven依赖的类文件
  • 自定义加载器:继承ClassLoader,并重写findClass方法。

类加载器的作用?

负责在类的加载过程中,获取字节码文件并加载到内存中。通过加载字节码数据转换为byte[]数组,接下来调用虚拟机底层方法将byte[]数组转换成方法区和堆中的数据。

2、双亲委派机制
2.1 双亲委派机制为了解决什么问题?

核心是为了解决一个类到底是由哪个类加载器来加载

2.2 介绍一下双亲委派机制?

当一个类加载器需要去加载类时,会 首先委派给其父类加载器进行加载,如果父类加载器无法加载,才由该类加载器自己去加载

2.3、双亲委派机制有什么好处?

这种层级关系使得类加载器能实现类的共享,避免类被重复加载,

提高了代码的安全性和可靠性,避免恶意覆盖jdk的核心类库。

比如,你重写了java.lang.String类,因为双亲委派模型机制,jvm只会通过bootstrap类加载器加载jre/lib包下的String类,由于父类加载器已经加载过这个类,就不会重复加载自己定义的,这样一定程度上保障了jvm的安全。

2.4、双亲委派机制有什么缺点?

有时候,需要多次加载同名的目录下的类,比如,当在Tomcat上部署多个服务时,不同服务可能依赖了不同版本的第三方jar,如果使用双亲委派机制进行加载,那么多个服务中的第三方jar就只会加载一次,那么依赖另外一个版本的jar的服务就有可能产生异常。

为了解决这种情况,需要打破双亲委派机制,不在让父类加载器加载,而是每个服务创建自己的子类加载器。

3、双亲委派机制原理?

不多说,看代码

java.lang.ClassLoader

public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // 能够查到类,就说明类已经被加载了,直接返回了。
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                // 双亲委派机制就在这里,如果父加载器不为空,就调用父加载器来尝试加载类
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else {
                    // 拓展类加载器的父加载器是null,
                    // 但是上层还有一个C++实现的启动类加载器
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {

            }

            // 父加载器没有加载到,就自己尝试加载
            if (c == null) {
                long t1 = System.nanoTime();
                // 加载方法,protected修饰的,因此如果自定义类加载器,不想破坏双亲委派模型的话,就重写这个方法
                c = findClass(name);

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        // resolveClass方法就是类加载阶段的连接 阶段,loadClass方法是赋值为false的,不会进行连接
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

4、如何破坏双亲委派机制呢?
4.1:自定义类加载器,重写loadClass方法

但是如果只为了定义自定义加载器,建议重写findClass方法,这样不会破坏双亲委派机制。

public class MyClassLoader extends ClassLoader {
    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        // 核心类库还是交给双亲委派机制进行加载
        if (name.startsWith("java.")) {
            super.loadClass(name);
        }
        
        // 通过类的全限定名,找到字节码文件,并转为byte数组 不写了
        byte[] data  = loadClassData(name);
        
        // 类的加载就是由defineClass这个底层方法实现的。
        return defineClass(name, data, 0, data.length);
    }
}

4.2 打破双亲委派机制的另外一种案例:JDBC

介绍:JDBC中使用了DriverManger来管理项目中引入的不同数据库的驱动,比如mysql,oracle驱动等。DriverManger这个类,位于rt.jar包中,由启动类加载器进行加载。但是DriverManger这个类是要去加载引入的jar包中的驱动类的,但是引入的jar包应该是由应用程序类加载器加载的,

这就出现了一个问题:启动类加载器加载完成DriverManger后,会委托应用类加载器去加载jar包中的驱动。这种委托关系就打破了双亲委派机制。

DriverManger怎么知道jar包中要加载的驱动在哪里?

spi机制(service provider interface),jdk内置的一种服务发现机制。查找classpath路径下的META-INF/services 文件夹下面的文件,并自动加载文件里所定义的类(这个文件中定义的就是需要加载的类的全限定名称).

这个文件中定义的就是需要加载的类的全限定名称,在JDBC中,比如mysql,oracle等第三方jar包驱动,就在META-INF/services 文件下面定义了以接口为名称的文件,文件内容就是对接口具体的实现类。

在springboot中,会引入一些其他依赖,自动注入的过程中,因为第三方jar包类和当前启动项不在一个包中,所以不能通过扫描进行注入,而且注入也要尽可能的和第三方依赖解耦。

springboot就规定了在META-INF文件夹中可以定义spring.factories文件,项目启动的时候会遍历所有jar包中的spring.factories,将里面定义的类加载到IOC中。

---- 上述就是springboot 中SPI机制的实现。

4.3 怎么理解JDBC案例中打破双亲委派机制?
  1.  首先是DriverManager这个类,是由启动类加载器加载的,毫无疑问符合双亲委派机制
  2. DriverManager加载驱动类时,不知道这些驱动类在哪里(比如引入了mysql或者oracle),就在初始化阶段的时候通过SPI机制去寻找,把加载这些类交给了应用类加载器去加载。(问题就出在这里了,启动类加载器委托应用类加载器去加载具体的驱动类。从这一层理解,好像是打破了双亲委派机制。)
  3. 但是启动类加载器知道要加载哪些类了之后,加载这些类的过程,还是符合双亲委派机制的。
  4. 通过上面的描述,JDBC是否打破双亲委派机制这个事情,见仁见智吧。

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

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

相关文章

基于Python微博舆情数据爬虫可视化分析系统(NLP情感分析+爬虫+机器学习)

这里写目录标题 基于Python微博舆情数据爬虫可视化分析系统(NLP情感分析爬虫机器学习)一、项目概述二、微博热词统计析三、微博文章分析四、微博评论分析五、微博舆情分析六、项目展示七、结语 基于Python微博舆情数据爬虫可视化分析系统(NLP情感分析爬虫机器学习) 一、项目概…

Paper Digest|基于在线聚类的自监督自蒸馏序列推荐模型

论文标题&#xff1a; Leave No One Behind: Online Self-Supervised Self-Distillation for Sequential Recommendation 作者姓名&#xff1a; 韦绍玮、吴郑伟、李欣、吴沁桐、张志强、周俊、顾立宏、顾进杰 组织单位&#xff1a; 蚂蚁集团 录用会议&#xff1a; WWW 2024 …

python中pow()函数的使用

在Python中&#xff0c;pow() 函数用于计算指定数字的幂。它的语法如下&#xff1a; pow(x, y) 这个函数返回 x 的 y 次方。相当于 x**y。 pow() 函数也可以接受一个可选的第三个参数&#xff0c;用于指定一个取模值&#xff0c;即计算结果与该模值的余数。其语法如下&#…

Unity编辑器功能 将选中的文件夹复制一份到其他文件夹

[MenuItem("Ab包工具/将选中的文件移动到StreamingAssets文件夹下")] public static void MoveFireToStreamA() { //得到选中文件的数组 Object[] selectobj Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets); i…

U盘文件突然消失:原因分析与恢复策略

U盘遭遇“幽灵”之手&#xff0c;文件不翼而飞 你是否曾遭遇过这样的诡异情况&#xff1a;前一天还好好存放在U盘里的文件&#xff0c;第二天却突然消失得无影无踪&#xff1f;这简直就像是一场无声的灾难&#xff0c;令人措手不及。U盘作为我们日常工作和生活中不可或缺的数据…

I2C系列(三):软件模拟I2C读写24C02

一.目标 PC 端的串口调试软件通过 RS-485 与单片机通信&#xff0c;控制单片机利用软件模拟 I2C 总线对 EEPROM&#xff08;24C02&#xff09; 进行任意读写。 二.硬件简述 2.1 24C02硬件参数 24C02器件地址为0x50&#xff0c;存储容量为256字节&#xff0c;存储单元地址位数…

Docker安装xxl-job并整合到SpringBoot项目

1. 创建数据库 执行如下SQL语句创建相关表 CREATE database if NOT EXISTS xxl_job default character set utf8mb4 collate utf8mb4_general_ci; use xxl_job;SET NAMES utf8mb4; CREATE TABLE xxl_job_info (id int(11) NOT NULL AUTO_INCREMENT,job_group int(11) NOT NUL…

YOLOV8逐步分解(2)_DetectionTrainer类初始化过程

接上篇文章yolov8逐步分解(1)--默认参数&超参配置文件加载继续讲解。 1. 默认配置文件加载完成后&#xff0c;创建对象trainer时&#xff0c;需要从默认配置中获取类DetectionTrainer初始化所需的参数args&#xff0c;如下所示 def train(cfgDEFAULT_CFG, use_pythonFalse…

Java基础语法(二)

前言 Hello&#xff0c;大家好&#xff01;很开心与你们在这里相遇&#xff0c;我是一个喜欢文字、喜欢有趣的灵魂、喜欢探索一切有趣事物的女孩&#xff0c;想与你们共同学习、探索关于IT的相关知识&#xff0c;希望我们可以一路陪伴~ 1. 类型转换 1.1 自动类型转换 什么是自…

政安晨:专栏目录【TensorFlow与Keras机器学习实战】

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机器学习实战 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 本篇是作者政安晨的专栏《TensorFlow与Keras机器…

AI新工具 小模型也有大智慧Qwen1.5-MoE;大模型动态排行榜;马斯克更新Grok-1.5

✨ 1: Qwen1.5-MoE 阿里巴巴一款小型 MoE 模型&#xff0c;只有 27 亿个激活参数&#xff0c;但性能与最先进的 7B 模型&#xff08;如 Mistral 7B 和 Qwen1.5-7B&#xff09;相匹配。 Qwen1.5-MoE是一个使用混合专家模型&#xff08;Mixture-of-Experts&#xff0c;MoE&…

H5实现3D旋转照片墙教程

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

从关键词到上下文:GPT 如何重新定义 SEO 策略

如何利用GPT技术革新SEO内容创建&#xff1f; 新的 SEO 格局 探索 SEO 的快速变化&#xff0c;重点关注从以关键字为中心的策略到更深入地了解用户意图和上下文的转变。 GPT 简介及其对内容创建、用户参与和搜索引擎优化 (SEO) 的革命性影响。 了解 GPT&#xff1a;技术范式转…

Stable Diffusion 模型下载:epiCPhotoGasm(真实、照片)

本文收录于《AI绘画从入门到精通》专栏&#xff0c;专栏总目录&#xff1a;点这里&#xff0c;订阅后可阅读专栏内所有文章。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八 下载地址 模型介绍 该模型对照片是什么有很高的了解&#xff0c;所以…

Stable Diffusion之核心基础知识和网络结构解析

Stable Diffusion核心基础知识和网络结构解析 一. Stable Diffusion核心基础知识1.1 Stable Diffusion模型工作流程1. 文生图(txt2img)2. 图生图3. 图像优化模块 1.2 Stable Diffusion模型核心基础原理1. 扩散模型的基本原理2. 前向扩散过程详解3. 反向扩散过程详解4. 引入Late…

农学院智慧农业产教融合基地解决方案

第一章 背 景 1.1国际数字农业发展概况 随着全球信息化、智能化技术的快速发展&#xff0c;数字农业作为现代农业发展的重要方向&#xff0c;正日益受到国际社会的广泛关注。数字农业依托物联网、大数据、云计算、人工智能等现代信息技术&#xff0c;实现农业生产全过程的智能…

软件接口安全设计规范及审计要点

1.token授权安全设计 2.https传输加密 3.接口调用安全设计 4.日志审计里监控 5.开发测试环境隔离&#xff0c;脱敏处理 6.数据库运维监控审计 项目管理全套资料获取&#xff1a;软件开发全套资料_数字中台建设指南-CSDN博客

GRE、VPN实验报告

一、实验拓扑图 二、实验要求 1、按照图示配置IP地址 2、在R1和R3上配置默认路由使公网区域互通 3、在R1和R3上配置GRE VPN&#xff0c;使两端私网能够互相访问&#xff0c;Tunnel口IP地址如图 4、在R1和R3上配置RIPv2或者ospf或者静态&#xff0c;来传递两端私网路由 三、…

golang import引用项目下其他文件内函数

初始化项目 go mod init [module名字] go mod init project 项目结构 go mod 文件 代码 需要暴露给外界使用的变量/函数名必须大写 在main.go中引入&#xff0c;当前项目模块名/要引用的包名 package mainimport (// 这里的路径开头为项目go.mod中的module"project/…

OpenGL的MVP矩阵理解

OpenGL的MVP矩阵理解 右手坐标系 右手坐标系与左手坐标系都是三维笛卡尔坐标系&#xff0c;他们唯一的不同在于z轴的方向&#xff0c;如下图&#xff0c;左边是左手坐标系&#xff0c;右边是右手坐标系 OpenGL中一般用的是右手坐标系 1.模型坐标系&#xff08;Local Space&…