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

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.hqwc.cn/news/577547.html

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

相关文章

工厂能耗管控物联网解决方案

工厂能耗管控物联网解决方案 工厂能耗管控物联网解决方案是一种创新的、基于先进技术手段的能源管理系统&#xff0c;它深度融合了物联网&#xff08;IoT&#xff09;、云计算、大数据分析以及人工智能等前沿科技&#xff0c;以实现对工业生产过程中能源消耗的实时监测、精确计…

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

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

遥控智能小车的功能内容有哪些?

东莞市酷得智能科技有限公司&#xff08;以下简称&#xff1a;酷得&#xff09;2018年成立于松山湖&#xff0c;且在汕头设立办事处。是一家创新型智能电子产品的整体解决方案服务商。酷得也是国内多家优秀芯片厂商的核心代理商&#xff0c;芯片的年出货量在8000万颗以上。包含…

python中raise_for_status方法的作用

文章目录 说明示例1&#xff1a;基本使用示例2&#xff1a;多种异常 说明 raise_for_status() 方法在 Python 的 requests 库中用于在发送 HTTP 请求后检查响应的状态码。如果响应的状态码表示请求未成功&#xff08;即状态码不是 2xx&#xff09;&#xff0c;则该方法会抛出一…

Python车道线偏离预警

程序示例精选 Python车道线偏离预警 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《Python车道线偏离预警》编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;易读。 学习与应用推…

C语言例4-35:鸡翁一,值钱五;鸡母一,值钱三;鸡雏三,值钱一。百钱买百鸡、问鸡翁、鸡母和鸡雏各几何?

方法一&#xff1a; 代码如下&#xff1a; //鸡翁一&#xff0c;值钱五&#xff1b;鸡母一&#xff0c;值钱三&#xff1b;鸡雏三&#xff0c;值钱一。百钱买百鸡、问鸡翁、鸡母和鸡雏各几何&#xff1f; //方法一&#xff1a; #include<stdio.h> int main(void) {int x…

OpenGL的MVP矩阵理解

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

HarmonyOS实战开发-实现带有卡片的电影应用

介绍 本篇Codelab基于元服务卡片的能力&#xff0c;实现带有卡片的电影应用&#xff0c;介绍卡片的开发过程和生命周期实现。需要完成以下功能&#xff1a; 元服务卡片&#xff0c;用于在桌面上添加2x2或2x4规格元服务卡片。关系型数据库&#xff0c;用于创建、查询、添加、删…

主从复制与读写分离

前言&#xff1a; 在企业应用中&#xff0c;成熟的业务通常数据量都比较大&#xff0c;单台MySQL在安全性、高可用性和高并发方面 都无法满足实际的需求&#xff1f; 配置多台主从数据库服务器以实现读写分离 一 主从复制的工作原理 ①Master节点将数据的改变记录成二进制…

使用Zabbix监控NAS目录状态

在企业的数据存储和共享中,网络附加存储(NAS)扮演着至关重要的角色。为了确保NAS设备的稳定运行和数据的完整性,对其进行实时监控是必不可少的。Zabbix作为一款开源的网络监控解决方案,能够帮助我们实现这一目标。本文将介绍如何使用Zabbix监控NAS目录状态,以确保及时发现…

Java_20 元素和最小的山形三元组

元素和最小的山形三元组 给你一个下标从 0 开始的整数数组 nums 。 如果下标三元组 (i, j, k) 满足下述全部条件&#xff0c;则认为它是一个 山形三元组 &#xff1a; i < j < knums[i] < nums[j] 且 nums[k] < nums[j] 请你找出 nums 中 元素和最小 的山形三元…

使用mybatis的@Interceptor实现拦截sql

一 mybatis的拦截器 1.1 拦截器介绍 拦截器是一种基于 AOP&#xff08;面向切面编程&#xff09;的技术&#xff0c;它可以在目标对象的方法执行前后插入自定义的逻辑。 1.2 语法介绍 1.注解Intercepts Intercepts({Signature(type StatementHandler.class, method “…