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

news/2024/4/27 20:05:13/文章来源:https://blog.csdn.net/qq_43325216/article/details/137088291
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.ClassLoaderpublic 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 statssun.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 {@Overridepublic 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.luyixian.cn/news_show_1028188.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯 java 凑算式 16年省赛Java组真题

题目 思路&#xff1a; 求有多少种解法 比如:68/3952/714就是一种解法&#xff0c;53/1972/486 是另一种解法 8/3952/714是可以除尽的 但是后面一个不行 所以我们也要通分 代码&#xff1a; public class 凑算式 {static int[] a {1, 2, 3, 4, 5, 6, 7, 8, 9};static int c…

SpringBoot Redis的使用

官方文档&#xff1a; 官方文档&#xff1a;Spring Data Redis :: Spring Data Redis 和jedis一样&#xff0c;SpringBoot Redis 也可以让我在Java代码中使用redis&#xff0c;同样也是通过引入maven依赖的形式。 加速访问github: 使用steam可以免费加速访问github Spring…

鸿蒙OS开发实例:【页面传值跳转】

介绍 本篇主要介绍如何在HarmonyOS中&#xff0c;在页面跳转之间如何传值 HarmonyOS 的页面指的是带有Entry装饰器的文件&#xff0c;其不能独自存在&#xff0c;必须依赖UIAbility这样的组件容器 如下是官方关于State模型开发模式下的应用包结构示意图&#xff0c;Page就是…

设计模式之单例模式精讲

UML图&#xff1a; 静态私有变量&#xff08;即常量&#xff09;保存单例对象&#xff0c;防止使用过程中重新赋值&#xff0c;破坏单例。私有化构造方法&#xff0c;防止外部创建新的对象&#xff0c;破坏单例。静态公共getInstance方法&#xff0c;作为唯一获取单例对象的入口…

ClickHouse 面试题及答案整理,最新面试题

ClickHouse的数据分布式存储机制是如何设计的&#xff1f; ClickHouse的数据分布式存储机制设计包括以下几个方面&#xff1a; 1、分片和复制&#xff1a; ClickHouse通过分片将数据水平划分为多个部分&#xff0c;每个部分存储在不同的节点上。每个分片可以有一个或多个副本…

macOS Sonoma 14.4.1 (23E224) 正式版发布,ISO、IPSW、PKG 下载

macOS Sonoma 14.4.1 (23E224) 正式版发布&#xff0c;ISO、IPSW、PKG 下载 2024 年 3 月 26 日凌晨&#xff0c;macOS Sonoma 14.4.1 更新修复了一个可能导致连接到外部显示器的 USB 集线器无法被识别的问题。它还解决了可能导致 Java 应用程序意外退出的问题&#xff0c;并修…

基于单片机音乐喷泉制作设计资料

**单片机设计介绍&#xff0c;基于单片机音乐喷泉制作设计资料 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机音乐喷泉制作设计资料概要主要包括以下几个关键部分&#xff1a;系统概述、硬件设计、软件设计以及实现过…

JavaScript高级 —— 学习(一)

目录 一、作用域 &#xff08;一&#xff09;局部作用域 1.函数作用域 2.块作用域 &#xff08;二&#xff09;全局作用域 二、垃圾回收机制 GC &#xff08;一&#xff09;生命周期 1.内存分配 2.内存使用 3.内存回收 4.特殊情况——内存泄漏&#xff1a; 注意&…

基于STC12C5A60S2系列1T 8051单片机通过单个按键单击次数实现开关机应用

基于STC12C5A60S2系列1T 8051单片机通过单个按键单击次数实现开关机应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍基于STC12C5A60S2系列1T 8051单片机通过单个按…

使用JMeter进行梯度压测

使用JMeter进行梯度压测 梯度压测配置如下&#xff1a; 使用线程:5&#xff0c;然后循环5000次&#xff0c;共2.5万个样本使用线程:10&#xff0c;然后循环5000次&#xff0c;共5万个样本使用线程:15&#xff0c;然后循环5000次&#xff0c;共7.5万个样本使用线程:20&#xff…

Git版本管理使用手册 - 8 - 合并分支、解决冲突

合并整个开发分支 切换到本地test分支&#xff0c;选择右下角远程开发分支&#xff0c;选择Merge into Current。然后提交到远程test仓库。 合并某次提交的代码 当前工作区切换成test分支&#xff0c;选择远程仓库中的dev开发分支&#xff0c;选择需要合并的提交版本右击&a…

AcWing 4609:火柴棍数字 ← 贪心算法

【题目来源】 https://www.acwing.com/problem/content/4612/【题目描述】 给定 n 个火柴棍&#xff0c;你可以用它们摆出数字 0∼9。 摆出每个数字所需要的具体火柴棍数量如下图所示&#xff1a; 请你用这些火柴棍摆成若干个数字&#xff0c;并把这些数字排成一排组成一个整数…

Git---命令筛选分支,分支过多快速定位分支!(值得收藏)

在Git中&#xff0c;有一些命令可以用来筛选分支&#xff0c;帮助我们找到特定的分支。 下面是一些常用的命令: git branch&#xff1a;列出所有本地分支。默认情况下&#xff0c;当前分支会用*标记。git branch -r&#xff1a;列出所有远程分支。git branch -a&#xff1a;列…

VTK 9.2.6 源码和VTK Examples 编译 Visual Studio 2022

对于编译 VTK 源码和编译详细的说明&#xff1a; VTK 源码编译&#xff1a; 下载源码&#xff1a; 从 VTK 官方网站或者 GitHub 获取源代码。官网目前最近的9.3.0有问题&#xff0c;见VTK 9.3.0 编译问题 Visual Studio 2022去gitlab上选择9.2.6分支进行clone CMake 配置&…

UI的设计

一、RGB888的显示 即红色&#xff0c;绿色&#xff0c;蓝色都为8位&#xff0c;即通常说的24位色。可以很好显示各种过渡颜色。从硬件上&#xff0c;R、G、B三基色的连接线各需要有8根&#xff0c;即24根数据线&#xff1b;软件上存储的数据量也需要24位&#xff0c;即3个字节&…

|行业洞察·趋势报告|《2024旅游度假市场简析报告-17页》

报告的主要内容解读&#xff1a; 居民收入提高推动旅游业发展&#xff1a;报告指出&#xff0c;随着人均GDP的提升&#xff0c;居民的消费能力增强&#xff0c;旅游需求从传统的观光游向休闲、度假游转变&#xff0c;国内人均旅游消费持续增加。 政府政策促进旅游市场复苏&…

代码随想录阅读笔记-二叉树【层序遍历】

题目 给你一个二叉树&#xff0c;请你返回其按 层序遍历 得到的节点值。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 思路 前面几篇博客中我们介绍了二叉树的递归遍历&#xff0c;迭代遍历以及统一迭代遍历&#xff0c;这三种遍历方式都属于二叉树…

springmvc自定义http请求状态码

1.背景 在做微信支付后回调时,微信要求: 接收成功&#xff1a; HTTP应答状态码需返回200或204&#xff0c;无需返回应答报文。 接收失败&#xff1a; HTTP应答状态码需返回5XX或4XX&#xff0c;同时需返回应答报文 微信通知文档:支付通知 - H5支付 | 微信支付商户文档中心 …

Elastic 8.13:Elastic AI 助手中 Amazon Bedrock 的正式发布 (GA) 用于可观测性

作者&#xff1a;来自 Elastic Brian Bergholm 今天&#xff0c;我们很高兴地宣布 Elastic 8.13 的正式发布。 有什么新特性&#xff1f; 8.13 版本的三个最重要的组件包括 Elastic AI 助手中 Amazon Bedrock 支持的正式发布 (general availability - GA)&#xff0c;新的向量…

2016年认证杯SPSSPRO杯数学建模C题(第二阶段)如何有效的抑制校园霸凌事件的发生全过程文档及程序

2016年认证杯SPSSPRO杯数学建模 C题 如何有效的抑制校园霸凌事件的发生 原题再现&#xff1a; 近年来&#xff0c;我国发生的多起校园霸凌事件在媒体的报道下引发了许多国人的关注。霸凌事件对学生身体和精神上的影响是极为严重而长远的&#xff0c;因此对于这些情况我们应该…