当前位置: 首页 > news >正文

【JVM从入门到实战】(六)类加载器的双亲委派机制

一、双亲委派机制

在Java中如何使用代码的方式去主动加载一个类呢?

方式1:使用Class.forName方法,使用当前类的类加载器去加载指定的类。
方式2:获取到类加载器,通过类加载器的loadClass方法指定某个类加载器加载。

双亲委派机制:自底向上查找是否加载过,再由顶向下进行加载
在类加载的过程中,每个类加载器都会先检查是否已经加载了该类,如果已经加载则直接返回,否则会将加载请求委派给父类加载器。如果类加载的parent为null,则会提交给启动类加载器处理。如果所有的父类加载器都无法加载该类,则由当前类加载器自己尝试加载。所以看上去是自顶向下尝试加载。第二次再去加载相同的类,仍然会向上进行委派,如果某个类加载器加载过就会直接返回。

面试题:类的双亲委派机制是什么?
当一个类加载器去加载某个类的时候,会自底向上向父类查找是否加载过,如果加载过就直接返回,如果一直到最顶层的类加载器都没有加载,再由顶向下进行加载

应用程序类加载器的父类加载器是扩展类加载器,扩展类加载器的父类加载器是启动类加载器

双亲委派机制的好处有两点:
1)避免恶意代码替换JDK中的核心类库,比如Java.lang.String,确保核心类库的完整性和安全性
2)避免类重复地被加载
在这里插入图片描述

Arthas中类加载器相关的功能:

类加载器的继承关系可以通过classloader –t 查看
在这里插入图片描述

如何打破双亲委派机制?

在这里插入图片描述

1. 打破双亲委派机制–自定义类加载器:tomcat

一个Tomcat程序中是可以运行多个Web应用的,如果这两个应用中出现了相同限定名的类,比如Servlet类,
Tomcat要保证这两个类都能加载并且它们应该是不同的类。如果不打破双亲委派机制,当应用类加载器加载Web应用1中的MyServlet之后,Web应用2中相同限定名的MyServlet类就无法被加载了。

Tomcat使用了自定义类加载器来实现应用之间类的隔离。每一个应用会有一个独立的类加载器加载对应的类。
在这里插入图片描述

下面2图为双亲委派机制的核心方法
在这里插入图片描述
在这里插入图片描述

自定义类加载器的父类是AppClassLoader

两个自定义类加载器加载相同限定名的类,不会冲突吗?
不会冲突,在同一个Java虚拟机中,只有相同类加载器+相同的类限定名才会被认为是同一个类。

在Arthas中使用sc –d 类名的方式查看具体的情况

2. 打破双亲委派机制-线程上下文类加载器:利用上下文类加载器加载类,比如JDBC和JNDI等

JDBC案例:JDBC中使用了DriverManager来管理项目中引入的不同数据库的驱动,比如mysql驱动、oracle驱动。下图
在这里插入图片描述
DriverManager类位于rt.jar包中,由启动类加载器加载。用户jar包中的驱动如依赖中的mysql驱动对应的类,由应用程序类加载器来加载。这就违反了双亲委派机制。
但DriverManager如何知道jar包中要加载的驱动在哪儿?
这里的DriverManage使用SPI机制(service-provider-interface),最终加载jar包中对应的驱动类。SPI中使用了线程上下文中保存的类加载器进行类的加载,这个类加载器一般是应用程序类加载器。
在这里插入图片描述

SPI机制:java菜鸟到大佬——全网最全SPI机制讲解 - 掘金
JDBC案例DriverManager管理用户类的加载的整体流程:

  1. 启动类加载器加载DriverManager。
  2. 在初始化DriverManager时,通过SPI机制加载jar包中的myql驱动。
  3. SPI中利用了线程上下文类加载器(应用程序类加载器)去加载用户类并创建对象。
    这种由启动类加载器加载的类,委派应用程序类加载器去加载类的方式,打破了双亲委派机制。
3. 打破双亲委派机制-OSGi模块化

历史上Osgi框架实现了一套新的类加载器机制,它存在同级之间的类加载器的委托加载。OSGi还使用类加载器实现了热部署的功能。热部署指的是在服务不停止的情况下,动态地更新字节码文件到内存中。
在这里插入图片描述

案例:使用阿里arthas不停机解决线上问题

背景:
小李的团队将代码上线之后,发现存在一个小bug,但是用户急着使用,如果重新打包再发布需要一个多小时的时间,所以希望能使用arthas尽快的将这个问题修复

思路:

  1. 在出问题的服务器上部署一个 arthas,并启动。
  2. jad --source-only 类全限定名 > 目录/文件名.java
    jad 命令反编译,然后可以用其它编译器,比如 vim 来修改源码
  3. mc –c 类加载器的hashcode 目录/文件名.java -d 输出目录
    mc 命令用来编译修改过的代码
  4. retransform class文件所在目录/xxx.class
    用 retransform 命令加载新的字节码

注意事项:
1、程序重启之后,字节码文件会恢复,除非将class文件放入jar包中进行更新。
2、使用retransform不能添加方法或者字段,也不能更新正在执行中的方法。

JDK8之后的类加载器

由于JDK9引入了module的概念,类加载器在设计上发生了很多变化。
1. 启动类加载器使用Java编写,位于jdk.internal.loader.ClassLoaders类中
Java中的BootClassLoader继承自BuiltinClassLoader实现从模块中找到要加载的字节码资源文件。
启动类加载器依然无法通过java代码获取到,返回的仍然是null,保持了统一。
2. 扩展类加载器被替换成了平台类加载器(Platform Class Loader)
平台类加载器遵循模块化方式加载字节码文件,所以继承关系从URLClassLoader变成了BuiltinClassLoader,BuiltinClassLoader实现了从模块中加载字节码文件。平台类加载器的存在更多的是为了与老版本的设计方案兼容,自身没有特殊的逻辑。

小结

1. 类加载器的作用是什么?

类加载器(ClassLoader)负责在类加载过程中的字节码获取并加载到内存这一部分。通过加载字节码数据放入内存转换成byte[],接下来调用虚拟机底层方法将byte[]转换成方法区和堆中的数据。

2. 有几种类加载器?
  1. 启动类加载器(Bootstrap ClassLoader)加载核心类
  2. 扩展类加载器(Extension ClassLoader)加载扩展类
  3. 应用程序类加载器(Application ClassLoader)加载应用classpath中的类
  4. 自定义类加载器,重写findClass方法。
    JDK9及之后扩展类加载器(Extension ClassLoader)变成了平台类加载器(Platform ClassLoader)
    在这里插入图片描述
3. 什么是双亲委派机制?

每个Java实现的类加载器中保存了一个成员变量叫“父”(Parent)类加载器。自底向上查找是否加载过,再由顶向下进行加载。避免了核心类被应用程序重写并覆盖的问题,提升了安全性。
在这里插入图片描述

4. 怎么打破双亲委派机制?
  1. 重写loadClass方法,不再实现双亲委派机制。
  2. JNDI、JDBC、JCE、JAXB和JBI等框架使用了SPI机制+线程上下文类加载器。
  3. OSGi实现了一整套类加载机制,允许同级类加载器之间互相调用。

相关文章:

【JVM从入门到实战】(六)类加载器的双亲委派机制

一、双亲委派机制 在Java中如何使用代码的方式去主动加载一个类呢? 方式1:使用Class.forName方法,使用当前类的类加载器去加载指定的类。 方式2:获取到类加载器,通过类加载器的loadClass方法指定某个类加载器加载。 …...

SpringCloud面试题及答案(最新50道大厂版,持续更新)

在Java开发中,Spring Cloud作为微服务架构的关键组成部分,为了帮助广大Java技术爱好者和专业开发人员深入理解Spring Cloud,本文《SpringCloud面试题及答案(最新50道大厂版,持续更新)》提供了最前沿、最实用…...

Next.js 的设计理念

Next.js 的设计理念:简洁、强大与高效 Next.js 是一个流行的 React 框架,由 Vercel 公司开发。它的设计理念是简洁、强大和高效,这种理念贯穿于 Next.js 的所有功能中。下面我们将深入探讨这三个设计理念。 简洁 Next.js 的一个核心设计理…...

26、文件包含

文章目录 一、文件包含1.1 概念1.2 PHP文件包含原理1.3 文件包含重要函数1.4 文件包含利用条件 二、文件包含漏洞利用2.1 文件包含分类2.2 常见敏感文件2.3 包含Apache日志文件2.4 常见中间件的日志路径2.5 包含其他日志文件2.5.1 SSH日志文件2.5.2 Session文件 三、PHP封装伪协…...

飞天使-linux操作的一些技巧与知识点4-ansible常用的技巧,配置等

文章目录 ansible配置文件的优先级尝试开始进行操作ansible常用模块ansible 的playbook示例安装phpplaybook中变量的引用 ansible yum install -y ansible 测试是否可用 ansible localhost -m ping /etc/ansible/ansible.cfg :主配置文件,配置 ansible…...

Stable Diffusion 源码解析(1)

参考1:https://blog.csdn.net/Eric_1993/article/details/129393890 参考2:https://zhuanlan.zhihu.com/p/613337342 1.StableDiffusion基本原理1.1 UNetModel、FrozenCLIP 模型1.2 DDPM、DDIM、PLMS算法 2. Runwayml SD 源码2.1 Img2Img Pipeline2.2 DD…...

java.lang.ClassNotFoundException:javax.xml.bind.DatatypeConverter 报错解决

问题原因: 这有可能是因为SpringBoot项目结合jwt进行用户登录时出现的问题&#xff0c;因为jdk版本太高导致的 解决办法: 方法一: 降低jdk版本 检查JDK版本,如果你是JDK17版本,就降到JDK8版本 方案二:在meven中添加依赖 注意: 如果2.3.1的版本不生效,则使用2.3.0的版本 <…...

Python学习笔记-类

1 定义类 类是函数的集合&#xff0c;class来定义类 pass并没有实际含义&#xff0c;只是为了代码能执行通过&#xff0c;不报错而已&#xff0c;相当于在代码种占一个位置&#xff0c;后续完善 类是对象的加工厂 2.创建对象 carCar()即是创建对象的过程 3、类的成员 3.1 实例…...

了解如何在linux使用podman管理容器

本章主要介绍使用 podman 管理容器。 了解什么是容器&#xff0c;容器和镜像的关系 安装和配置podman 拉取和删除镜像 给镜像打标签 导出和导入镜像 创建和删除镜像 数据卷的使用 管理容器的命令 使用普通用户管理容器 使用普通用户管理容器 对于初学者来说&#xff0c;不太容…...

SQL命令---修改字段的数据类型

介绍 使用sql语句修改字段的数据类型。 命令 alter table 表明 modify 字段名 数据类型;例子 有一张a表&#xff0c;表里有一个id字段&#xff0c;长度为11。使用命令将长度修改为12 下面使用命令进行修改&#xff1a; alter table a modify id int(12) NOT NULL;下面使修…...

一键提取微信聊天记录,生成HTML、Word文档永久保存,还能生成微信年度聊天报告

不知道生活中你有没有遇到过这种情况&#xff0c;聊天记录不完整&#xff0c;有的在手机上&#xff0c;有的在电脑上&#xff0c;搜索起来很烦。那有没有一种办法可以把微信聊天记录统一呢&#xff1f;当然是有的。下面&#xff0c;就让我们一起来看一下怎么操作。 先看效果 操…...

docker使用详解

介绍 Docker是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中&#xff0c;然后发布到任何流行的Linux或Windows操作系统的机器上&#xff0c;也可以实现虚拟化。 Docker基于轻量级虚拟化技术&#xff0c;整个项目基于Go语言开…...

MidJourney笔记(7)-Seeds

我相信很多人在使用MidJourney的时候,都会遇到一个问题,就是如何保持生成图像的一致性,或者相对一致性,差异性不是很大。此时,我们就需要引入一个seed值,类似给这个提示词生成的图片做一个id标识。 那这个seed值怎么使用? 其实,在我们每次生成的图片,都有有一个seed值…...

pom配置文件重要标签探究

文章目录 dependencies标签dependencyManagement标签两者辨析repositories标签properties标签 dependencies标签 <dependencies>标签用于指定项目的依赖项列表。这些依赖项可以是应用程序代码所需的库&#xff0c;也可以是Spring Boot和其他第三方库。<dependencies&…...

如何在Ubuntu的Linux系统上搭建nacos集群

官方给出的集群部署架构图 集群部署说明 (nacos.io)3个或3个以上nacos节点才能构成集群当前示例中包含3个nacos节点&#xff0c;同时一个负载均衡器代理3个nacos&#xff0c;本示例中负载均衡器可使用的是nginx 准备并安装好正常运行的nginx&#xff0c;本示例略准备并安装好正…...

oracle中的PIVOT函数

在Oracle数据库中&#xff0c;PIVOT 是一个强大的功能&#xff0c;可以将行数据转换为列数据。这在报表和数据分析中非常有用。 基本的 PIVOT 语法如下&#xff1a; SELECT * FROM (SELECT <column1>, <column2>, ..., <pivot_column>, <aggregate_func…...

【经验分享】gemini-pro和gemini-pro-vision使用体验

Gemini Gemini已经对开发者开放了Gemini Pro的使用权限&#xff0c;目前对大家都是免费的&#xff0c;每分钟限制60条&#xff0c;至少这比起CloseAI的每个账户5刀限速1min3条要香的多&#xff0c;目前已于第一时间进行了体验 一句话总结&#xff0c;google很大方&#xff0c;但…...

JS冒泡排序

想必大家都多多少少了解过一点排序&#xff0c;让我为大家介绍一下冒泡排序吧&#xff01; 假设我们现在有一个数组[2&#xff0c;4&#xff0c;3&#xff0c;5&#xff0c;1] 我们来分析一下&#xff1a; 1.一共需要的趟数 我们用外层for循环 5个数据我们一共需要走4躺 长度就…...

面向遥感图像的道路区域提取及优化

一、论文2017 (1)DeepRoadMapper (2)Topology Loss2018 (1)RoadTracer (2)iterative-deep-learning2019 (1)Leveraging Crowdsourced GPS Data for Road Extraction from Aerial Imagery (2)RoadNet (3)RoadTagger (4)Generative Graph Transformer (5)road_…...

mysql中NULL值

mysql中NULL值表示“没有值”&#xff0c;它跟空字符串""是不同的 例如&#xff0c;执行下面两个插入记录的语句&#xff1a; insert into test_table (description) values (null); insert into test_table (description) values ();执行以后&#xff0c;查看表的…...

[c++] 意识需要转变的一个例子,全局变量的构造函数先于main执行

最近还遇到一个例子是关于&#xff1a;从C转C开发需要注意的一个意识问题。本人遇到的这个问题是&#xff0c;带着C的意识来看C的代码&#xff0c;然后根据代码看&#xff0c;有一个全局变量的值在main函数进入之后才会更改&#xff0c;所以百思不得其解&#xff0c;这个变量怎…...

VSCode 配置自动生成头文件

相关文章 VSCode 开发C/C实用插件分享——codegeex VSCode 开发C/C实用插件分享——koroFileHeader VSCode 配置自动生成头文件 一、snippets二、配置步骤三、效果展示 一、snippets 相信大家对C、C都头文件都不陌生&#xff0c;都会发现每个头文件都会包括下面的这些格式&…...

【大数据】Hudi 核心知识点详解(一)

&#x1f60a; 如果您觉得这篇文章有用 ✔️ 的话&#xff0c;请给博主一个一键三连 &#x1f680;&#x1f680;&#x1f680; 吧 &#xff08;点赞 &#x1f9e1;、关注 &#x1f49b;、收藏 &#x1f49a;&#xff09;&#xff01;&#xff01;&#xff01;您的支持 &#x…...

windows上抓包出现大包未分片以及关闭tso方法

wireshark抓包中会有大数据包&#xff08;未分片包&#xff09;和ip校验和不对的包&#xff0c;问题根因在目前很多电脑网卡支持TSO和将校验和计算到网卡上&#xff0c;导致抓出数据包未分片 详细文章看: https://www.cnblogs.com/charlieroro/p/11363336.html 目前很多网卡已…...

Leetcode 2454. 下一个更大元素 IV

Leetcode 2454. 下一个更大元素 IV题目 给你一个下标从 0 开始的非负整数数组 nums 。对于 nums 中每一个整数&#xff0c;你必须找到对应元素的 第二大 整数。如果 nums[j] 满足以下条件&#xff0c;那么我们称它为 nums[i] 的 第二大 整数&#xff1a; j >nums[j] > nu…...

浏览器全屏按键同f11效果

模拟键f11 // for IE&#xff0c;这里和fullScreen相同&#xff0c;模拟按下F11键退出全屏 let wscript new ActiveXObject(WScript.Shell) if (wscript ! null) {wscript.SendKeys({F11}) }同f11键效果生效全屏函数 //判断是否是全屏状态 var isFull Math.abs(window.scree…...

CentOS 7.9 安装 k8s(详细教程)

&#x1f37f;安装步骤 &#x1f35a;安装前准备事项&#x1f35a;安装docker&#x1f35a;删除docker&#x1f35a;安装yum工具&#x1f35a;设置docker镜像源&#x1f35a;安装指定版本docker&#x1f35a;设置开启自启&#x1f35a;阿里云镜像加速 &#x1f35a;准备环境&am…...

区块链的可拓展性研究【05】闪电网络

1.闪电网络&#xff1a;闪电网络是一种基于比特币区块链的 Layer2 扩容方案&#xff0c;它通过建立一个双向支付通道网络&#xff0c;实现了快速、低成本的小额支付。闪电网络的交易速度非常快&#xff0c;可以达到每秒数万笔交易&#xff0c;而且交易费用非常低&#xff0c;几…...

如何部署Portainer容器管理工具+cpolar内网穿透实现公网访问管理界面

文章目录 前言1. 部署Portainer2. 本地访问Portainer3. Linux 安装cpolar4. 配置Portainer 公网访问地址5. 公网远程访问Portainer6. 固定Portainer公网地址 前言 本文主要介绍如何本地安装Portainer并结合内网穿透工具实现任意浏览器远程访问管理界面。Portainer 是一个轻量级…...

Linux——Samba文件共享服务配置

SMB/CIFS协议 SMB协议(Server Message Block 又称Common Internet File System&#xff08;CIFS&#xff09;) 是由微软开发的网络传输协议&#xff0c;用来实现网络共享文件系统、打印机等资源。 SMB协议有多个版本和不同的兼容性。 SMBv1/CIFS: 也称为SMB1或CIFS。最初由Micr…...