JVM-类加载器 双亲委派机制

申明:文章内容是本人学习极客时间课程所写,文字和图片基本来源于课程资料,在某些地方会插入一点自己的理解,未用于商业用途,侵删。

什么是JVM

JVM是Java Virtual Machine(Java虚拟机)的缩写,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域等组成。JVM屏蔽了与操作系统平台相关的信息,使得Java程序只需要生成在Java虚拟机上运行的目标代码(字节码),就可在多种平台上不加修改的运行,这也是Java能够“一次编译,到处运行的”原因。

在这里插入图片描述

类加载

类加载器的定义(深入理解JVM原话):
通过一个类的全限定名称来描述此类的二进制字节流,将这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定获取所需要的类,实现这个动作的代码模快称为类加载器。
1 JVM 的类加载是通过ClassLoader及子类来完成的,通常来说有下面几种类加载器:

  • 启动类加载器(Bootstrap ClassLoader)
    负责加载JAVA_ HOME\lib目录的或通过-Xbootclasspath参数指定路径中的且被虚拟机认可(rt.jar) 的类库。由C++实现,不是ClassLoader的子类
  • 扩展类加载器(Extension ClassLoader)
    负责加载JAVA_ _HOME\lib\ext目录或通过java.ext.dirs系统变量指定路径中的类库
  • 应用程序类加载器(Application ClassLoader)
    负责加载用户路径classpath上的类库
  • 自定义类加载器
    JVM 只能加载放在指定路径下的字节码,某些时候我们需要加载自己的class文件就需要用到自定义类加载器。

2 类加载执行顺序
检查顺序是自底向上:加载过程中会先检查类是否被已加载,从Custom到BootStrap逐层检查,只要某个类加载器已加载就视为此类已加载,保证此类所有ClassLoader只加载一 次.
在这里插入图片描述
3 加载时机(检查时自底向上,加载时自顶向下)

1-遇到new、getStatic、 putStatic、 invokeStatic四条指令时。
2-使用java.lang.reflect包方法时,对类进行反射调用。
3-初始化这个类时,发现其父类还没初始化,要先初始化其父类。
4-当虚拟机启动时,用户需要指定–个主类Main,需要先将主类加载。

4 一个类的一生
在这里插入图片描述

5 类加载所做的事情
在类加载的过程中,做了如下几件事情:
1 根据全限定名称加载二进制字节流。
2 将字节流转换为数据结构
3 创建字节码class的对象

6 类加载途径
➢01-jar/war
➢02-jsp生成的class
➢03-数据库中的二进制字节流
➢04-网络中的二进制字节流
➢05-动态代理生成的二进制字节流

在这里插入图片描述
自定义类加载器案例helloworld

public class CustomClassLoader extends ClassLoader {private final String classPath;public CustomClassLoader(String classPath) {this.classPath = classPath;}public static void main(String[] args) {CustomClassLoader customClassLoader = new CustomClassLoader("E:\\lesson-one\\lesson-one\\src\\lib");try {Class<?> c = customClassLoader.loadClass("com.learn.lessonone.dto.Test");if (c != null) {Object o = c.newInstance();Method say = c.getMethod("say", null);say.invoke(o, null);System.out.println(c.getClassLoader().toString());}} catch (Exception e) {e.printStackTrace();}}@Overrideprotected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {try {byte[] calsssDate = getData(name);if (calsssDate != null) {return defineClass(name, calsssDate, 0, calsssDate.length);}} catch (Exception e) {e.printStackTrace();}return super.loadClass(name, resolve);}@Overrideprotected Object getClassLoadingLock(String className) {return super.getClassLoadingLock(className);}public byte[] getData(String className) {String path = classPath + File.separator + className.replace(".", File.separator) + ".class";try (InputStream in = new FileInputStream(path);ByteArrayOutputStream out = new ByteArrayOutputStream()) {byte[] buffer = new byte[1024];int len = 0;while ((len = in.read(buffer)) != -1) {out.write(buffer, 0, len);}} catch (Exception e) {e.printStackTrace();}return null;}
}
类加载机制双亲委派

1-什么是双亲委派?
当一个类加载器收到类加载任务,会先交给其父类加载器去完成,因此最终加载任务都会传递到顶层的启动类加载器,只有当父类加载器无法完成加载任务时,才会尝试执行加载任务。

2-为什么需要双亲委派呢?
2-1 双亲委派其实是一种规范,它一定程度上能够保证安全性。就比如我们尝试用的Object,String类,如果我们没有委托父类进行加载,每个子类进行加载,如果这个时候我们自己写了一个类的全限定名称和系统的一模一样,这个时候它加载的就是我们写的类,这样就会导致我们使用的不是Java给我门头提供的Object类,从而程序完全乱套。
为什么双亲委派能够解决这个问题呢,因为我们会一直委托父类去加载,加载Object这种类最终都是由BootstrapClassLoader来加载,它保证了加载的一定是Java提供给我们的Object类,因为BootstrapClassLoader就是负责加载这类内置类的(也就是加载java 固定路径下的一些类)。
2-2 双亲委派可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
3-为什么还需要破坏双亲委派?
在实际应用中,双亲委派解决了Java 基础类统一加载的问题,但是却存在着缺陷。JDK中的基础类作为典型的API被用户调用,但是也存在API调用用户代码的情况,JNDI,SPI,这种情况就需要打破双亲委派模式。
例如:数据库驱动DriverManager。以Driver接口为例,Driver接口定义在]DK中,其实现由各个数据库的服务商来提供,由系统类加载器加载。这个时候就需要启动类加载器来委托子类来加载Driver实现,这就破坏了双亲委派。从下面这段源码来看,我们加载类加载DriverManager是由bootstracpClassLoader加载的,但是我们加载不同厂商的Driver是拿的线程的自定义类加载器去加载的。
在这里插入图片描述

4-如何破坏双亲委派?
方式一:重写ClassLoader的loadClass方法
方式二:SPl,类委托自类加载器加载Class,以数据库驱动DriverManager为例
方式三:为了满足热部署、不停机更新需求。OSGI 就是利用自定义的类加载器机制来完成模块化热部署,而它实
现的类加载机制就没有完全遵循自下而上的委托,有很多平级之间的类加载器查找。
自己的理解:
自定义的类始最终都是由ApplicationClassLoader或自定义类加载器加载比如我写了一个CustomObject 继承了Object这个类 并定义了这个类字段结构。在执行加载的时候,CustomObject一直向上委托,最后发现BootStrapClassLoaer加载不了,然后又自顶向下回溯ApplicationClassLoader来加载CustomObject这个类,但是Object BootStrapClassLoaer是能加载的,在回到这里之前Object已将被加载过了,因为它会被BootStrapClassLoader加载。
类加载的源码 可以类的加载时委托自己的父亲进行加载

protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// First, check if the class has already been loaded// 首先检查类是否已被加载Class<?> c = findLoadedClass(name);if (c == null) {long t0 = System.nanoTime();try {if (parent != null) {// 如果父亲存在则让父亲加载此类c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// ClassNotFoundException thrown if class not found// from the non-null parent class loader}if (c == null) {// If still not found, then invoke findClass in order// to find the class.long t1 = System.nanoTime();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();}}if (resolve) {resolveClass(c);}return c;}}

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

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

相关文章

DataBinding源码浅析---初始化过程

作为Google官方发布的支持库&#xff0c;DataBinding实现了UI组件和数据源的双向绑定&#xff0c;同时在Jetpack组件中&#xff0c;也将DataBinding放在了Architecture类型之中。对于DataBinding的基础使用请先翻阅前两篇文章的详细阐述。本文所用代码也是建立在之前工程基础之…

网络报文处理流程

报文处理流程 WLAN网络中的数据包括管理报文和业务数据报文。管理报文必须采用CAPWAP隧道进行转发&#xff0c;而业务数据报文除了可以采用CAPWAP隧道转发之外&#xff0c;还可以采用直接转发方式和Soft-GRE转发方式。 管理报文用来传送AC与AP之间的管理数据&#xff0c;存在于…

反应式编程

反应式编程 前言1 反应式编程概览2 初识 Reactor2.1 绘制反应式流图2.2 添加 Reactor 依赖 3.使用常见的反应式操作3.1 创建反应式类型3.2 组合反应式类型3.3 转换和过滤反应式流3.4 在反应式类型上执行逻辑操作 总结 前言 你有过订阅报纸或者杂志的经历吗?互联网的确从传统的…

BYTEVALUE 百为流控路由器远程命令执行漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

JavaWeb:SpringBootWeb登录认证 --黑马笔记

1.登录认证 登录认证&#xff0c;如果只是简单的判断用户名和密码在数据库中是否对应相等来实现这个需求是有问题的&#xff0c;它只是徒有其表&#xff0c;我们不登陆也可以访问后端系统页面&#xff0c;真正的登录功能应该是&#xff1a;登陆后才能访问后端系统页面&#xf…

Python - 面向对象编程 - 类变量、实例变量/类属性、实例属性

什么是对象和类 什么是 Python 类、类对象、实例对象 类变量、实例变量/类属性、实例属性 前言 只是叫法不一样 实例属性 实例变量 类属性 类变量 个人认为叫属性更恰当 类属性和实例属性区别 类属性&#xff0c;所有实例对象共享该属性实例属性&#xff0c;属于某一…

数据库恢复

文章目录 前言一、事务1.概念2.定义语句3.ACID特性 二、数据库恢复的必要性1.为什么要进行数据库恢复2.数据库恢复机制的作用 三、数据恢复使用的技术1.数据转储2.登记日志文件 四 、不同故障的数据恢复策略1.事务内部的故障2.系统故障3.介质故障 五、具有检查点的恢复技术1.检…

跟着pink老师前端入门教程-day24

四、移动端WEB开发之响应式布局 1、响应式开发 1.1 响应式开发原理 就是使用媒体查询针对不同宽度的设备进行布局和样式的设置&#xff0c;从而适配不同设备的目的。 1.2 响应式布局容器 响应式需要一个父级做为布局容器&#xff0c;来配合子级元素来实现变化效果。 原理…

springboot181基于springboot的乐享田园系统

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

CSS基础---新手入门级详解

CSS:层叠样式表 CSS&#xff08;Cascading Style Sheets,层叠样式表&#xff09;&#xff0c;是一种用来为结构化文档添加样式&#xff08;字体、间距和颜色&#xff09;的计算机语言&#xff0c;css扩展名为.css。 实例: <!DOCTYPE html><html> <head><…

通过容器化释放云的力量

NCSC (英国国家网络安全中心) 经常被问到的一个问题是是否在云中使用容器。这是一个简单的问题&#xff0c;但答案非常微妙&#xff0c;因为容器化的使用方式有很多种&#xff0c;其中一些方法比其他方法效果更好。 今天&#xff0c;我们发布了有关使用容器化的安全指南&#…

C++ //练习 5.19 编写一段程序,使用do while循环重复地执行下述任务:首先提示用户输入两个string对象,然后挑出较短的那个并输出它。

C Primer&#xff08;第5版&#xff09; 练习 5.19 练习 5.19 编写一段程序&#xff0c;使用do while循环重复地执行下述任务&#xff1a;首先提示用户输入两个string对象&#xff0c;然后挑出较短的那个并输出它。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#x…