JVM之类加载器

文章目录

  • 版权声明
  • 类加载器
  • 类加载器的分类
    • 启动类加载器
    • 拓展类加载器&应用程序类加载器
  • 双亲委派机制
    • 解决三个问题
  • 打破双亲委派机制
    • 自定义类加载器
    • 案例演示
    • 线程上下文类加载器
    • 案例梳理
    • OSGi模块化

版权声明

  • 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明,所有版权属于黑马程序员或相关权利人所有。本博客的目的仅为个人学习和交流之用,并非商业用途。
  • 我在整理学习笔记的过程中尽力确保准确性,但无法保证内容的完整性和时效性。本博客的内容可能会随着时间的推移而过时或需要更新。
  • 若您是黑马程序员或相关权利人,如有任何侵犯版权的地方,请您及时联系我,我将立即予以删除或进行必要的修改。
  • 对于其他读者,请在阅读本博客内容时保持遵守相关法律法规和道德准则,谨慎参考,并自行承担因此产生的风险和责任。本博客中的部分观点和意见仅代表我个人,不代表黑马程序员的立场。

类加载器

  • 类加载器(ClassLoader)是Java虚拟机提供给应用程序去实现获取类和接口字节码数据的技术。
  • 类加载器只参与加载过程中的字节码获取并加载到内存这一部分
    在这里插入图片描述
    在这里插入图片描述
  • 类加载器的应用场景
    在这里插入图片描述

类加载器的分类

  • 类加载器分为两类,一类是Java代码中实现的,一类是Java虚拟机底层源码实现的。
    -
  • 类加载器的设计JDK8和8之后的版本差别较大,JDK8及之前的版本中默认的类加载器有如下几种
    在这里插入图片描述
  • 类加载器的详细信息可以通过classloader命令查看:
    • classloader - 查看 classloader 的继承树,urls,类加载信息,使用 classloader 去getResource
    • 详细的指令教程请参考Arthas官网
[arthas@17048]$ classloadername                                       numberOfInstances  loadedCountTotalBootstrapClassLoader                       1                  2248com.taobao.arthas.agent.ArthasClassloader  1                  1351sun.misc.Launcher$ExtClassLoader           1                  47sun.reflect.DelegatingClassLoader          15                 15sun.misc.Launcher$AppClassLoader           1                  8
Affect(row-cnt:5) cost in 7 ms.
[arthas@17048]$ classloader -t
+-BootstrapClassLoader
+-sun.misc.Launcher$ExtClassLoader@7fe21cf8+-com.taobao.arthas.agent.ArthasClassloader@53e59711+-sun.misc.Launcher$AppClassLoader@18b4aac2
Affect(row-cnt:4) cost in 5 ms.
  • BootstrapClassLoader:c++编写的启动类加载器,位于虚拟机的源码中
    • numberOfInstances :1 类加载器的个数为一个
    • loadedCountTotal: 2248 共加载了2248个核心类
  • ArthasClassloader: ArthasClassloader工具的加载器
  • ExtClassLoader:拓展类加载器
  • DelegatingClassLoader: jdk底层实现用来提升反射效率的加载器
  • AppClassLoader:应用程序类加载器

启动类加载器

  • 启动类加载器(Bootstrap ClassLoader)是由Hotspot虚拟机提供的、使用C++编写的类加载器
  • 默认加载Java安装目录/jre/lib下的类文件,比如rt.jar,tools.jar,resources.jar等。
    在这里插入图片描述
  • 通过启动类加载器去加载用户jar包
    • 放入jre/lib下进行扩展:不推荐,尽可能不要去更改JDK安装目录中的内容,会出现即时放进去由于文件名不匹配的问题也不会正常地被加载
    • 使用参数进行扩展:推荐,使用-Xbootclasspath/a:jar包目录/jar包名 进行扩展

拓展类加载器&应用程序类加载器

  • 扩展类加载器和应用程序类加载器都是JDK中提供的、使用Java编写的类加载器

  • 它们的源码都位于sun.misc.Launcher中,是一个静态内部类,继承自URLClassLoader。通过目录或者指定jar包将字节码文件加载到内存中。
    在这里插入图片描述

  • 扩展类加载器(Extension Class Loader)是JDK中提供的、使用Java编写的类加载器

  • 默认加载Java安装目录/jre/lib/ext下的类文件

在这里插入图片描述

  • 通过扩展类加载器去加载用户jar包
    • 放入/jre/lib/ext下进行扩展:不推荐,尽可能不要去更改JDK安装目录中的内容
  • 使用参数进行扩展
    • 推荐,使用-Djava.ext.dirs=jar包目录 进行扩展,这种方式会覆盖掉原始目录,可以用;(windows):(macos/linux)追加上原始目录
  • 类加载器的加载路径可以先使用classloader -l查看类的hash值,然后通过classloader –c hash值 查看
    在这里插入图片描述

双亲委派机制

  • 由于Java虚拟机中有多个类加载器,那么一个类到底由哪个加载器进行加载?
  • 解决方案:双亲委派机制 双亲委派机制的核心是解决一个类到底由谁加载的问题
    在这里插入图片描述
  • 每个Java实现的类加载器中保存了一个成员变量叫“父”(Parent)类加载器,可以理解为它的上级,并不是继承关系。
    在这里插入图片描述
  • 启动类加载器使用C++编写,没有上级类加载器
  • 应用程序类加载器的parent父类加载器是扩展类加载器,而扩展类加载器的parent是空。扩展类加载器(Extension ClassLoader)在类加载过程中会委托给启动类加载器(Bootstrap ClassLoader)。这是因为Java的类加载器遵循所谓的"双亲委派模型"。
图1 真实的父类关系
图2 双亲委派机制中的逻辑关系
  • 尽管在类加载器的层次结构中,扩展类加载器的父类加载器是启动类加载器,但实际上,在类的加载过程中,应用类加载器的父类加载器是扩展类加载器,扩展类加载器没有父类加载器,但会委派给启动类加载器加载。这就是通常说扩展类加载器的父类加载器是启动类加载器。
  • 类加载器的继承关系可以通过classloader –t 查看
  • 双亲委派机制:当一个类加载器收到类加载请求时,它并不会尝试立即加载这个类,而是把这个请求委派给父类加载器。这样,每个类加载请求都会传递到启动类加载器,只有当父类加载器无法处理这个请求时(例如,类不在它的搜索路径中),子类加载器才会尝试自己去加载。

  • 双亲委派机制口诀:自底向上查找是否加载过,再由顶向下进行加载。
    在这里插入图片描述
    在这里插入图片描述

请添加图片描述
在这里插入图片描述

解决三个问题

  1. 重复的类:如果一个类重复出现在三个类加载器的加载位置,应该由谁来加载?
    • 启动类加载器加载,根据双亲委派机制,它的优先级是最高的
  2. String类覆盖问题:在自己的项目中去创建一个java.lang.String类,会被加载吗?
    • 不能,会交由启动类加载器加载在rt.jar包中的String类
  3. 类加载器的关系:这几个类加载器彼此之间存在关系吗?
    • 应用类加载器的父类加载器是扩展类加载器,扩展类加载器没有父类加载器,但是会委派给启动类加载器加载

打破双亲委派机制

  • 打破双亲委派机制的三种方式
  1. 自定义类加载器
    • 自定义类加载器并且重写loadClass方法,就可以将双亲委派机制的代码去除
  2. 线程上下文类加载器
    • Tomcat通过这种方式实现应用之间类隔离
  3. Osgi框架的类加载器
    • 历史上Osgi框架实现了一套新的类加载器机制,允许同级之间委托进行类的加载

自定义类加载器

  • 一个Tomcat程序中是可以运行多个Web应用的,如果这两个应用中出现了相同限定名的类,比如Servlet类,Tomcat要保证这两个类都能加载并且它们应该是不同的类。
  • 如果不打破双亲委派机制,当应用类加载器加载Web应用1中的MyServlet之后,Web应用2中相同限定名的MyServlet类就无法被加载。
    在这里插入图片描述
  • Tomcat使用了自定义类加载器来实现应用之间类的隔离。每一个应用会有一个独立的类加载器加载对应的类。
    在这里插入图片描述

  1. 先来分析ClassLoader的原理,ClassLoader中包含了4个核心方法
  2. 双亲委派机制的核心代码就位于loadClass方法中
    在这里插入图片描述
public Class<?> loadClass(String name) throws ClassNotFoundException {return this.loadClass(name, false); //resolve
}protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {//加锁 保证只有一个线程加载类synchronized(this.getClassLoadingLock(name)) {//查询当前类加载器是否加载过需要的类,true 返回类对象 否则,返回nullClass<?> c = this.findLoadedClass(name);if (c == null) {long t0 = System.nanoTime();//向逻辑父类委派加载任务try {//直到委派到顶级父类——Extension,进入else分支if (this.parent != null) {c = this.parent.loadClass(name, false);} else {//调用启动类加载器,进行加载,无法加载返回nullc = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException var10) {}//所有类加载器加载失败,使用本类加载器进行加载if (c == null) {long t1 = System.nanoTime();c = this.findClass(name);PerfCounter.getParentDelegationTime().addTime(t1 - t0);PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);PerfCounter.getFindClasses().increment();}}if (resolve) {this.resolveClass(c);}return c;}
}final Class<?> loadClass(Module module, String name) {synchronized(this.getClassLoadingLock(name)) {Class<?> c = this.findLoadedClass(name);if (c == null) {c = this.findClass(module.getName(), name);}return c != null && c.getModule() == module ? c : null;}
}
//读取二进制数据
protected Class<?> findClass(String name) throws ClassNotFoundException {throw new ClassNotFoundException(name);
}protected Class<?> findClass(String moduleName, String name) {if (moduleName == null) {try {return this.findClass(name);} catch (ClassNotFoundException var4) {}}return null;
}
//类名校验 将字节码信息加载到虚拟机内存中
protected final Class<?> defineClass(byte[] b, int off, int len) throws ClassFormatError {return this.defineClass((String)null, b, off, len, (ProtectionDomain)null);
}protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError {return this.defineClass(name, b, off, len, (ProtectionDomain)null);
}protected final void resolveClass(Class<?> c) {if (c == null) {throw new NullPointerException();}
}
  • 阅读双亲委派机制的核心代码,分析如何通过自定义的类加载器打破双亲委派机制
  • 打破双亲委派机制的核心就是将下边这一段代码重新实现
//parent等于null说明父类加载器是启动类加载器,直接调用findBootstrapClassOrNull
//否则调用父类加载器的加载方法
if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}
//父类加载器爱莫能助,我来加载!
if (c == null) c = findClass(name);

案例演示

public class CustomClassLoader extends ClassLoader {public CustomClassLoader(ClassLoader parent) {super(parent);}@Overridepublic Class<?> loadClass(String name) throws ClassNotFoundException {// 简单的例子, 只处理自定义的类if (name.startsWith("com.mydomain")) {return findClass(name);}// 其他的类还是采用双亲委派机制加载return super.loadClass(name);}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {try {byte[] bytes = loadClassData(name);return defineClass(name, bytes, 0, bytes.length);} catch (IOException e) {throw new ClassNotFoundException("Cannot load class " + name, e);}}private byte[] loadClassData(String name) throws IOException {// 根据类名加载类的二进制数据. 假设所有类都在一个固定的目录下Path path = Paths.get("classes", name.replace('.', '/') + ".class");return Files.readAllBytes(path);}}
  1. 自定义类加载器默认父类是AppClassLoader
  • 以Jdk8为例,ClassLoader类中提供了构造方法设置parent的内容
    在这里插入图片描述
  • 这个构造方法由另外一个构造方法调用,其中父类加载器由getSystemClassLoader方法设置,该方法返回的是AppClassLoader。
    在这里插入图片描述
  • 两个自定义类加载器加载相同限定名的类,不会冲突
    • 在同一个Java虚拟机中,只有相同类加载器+相同的类限定名才会被认为是同一个类

  • 正确的去实现一个自定义类加载器的方式是重写findClass方法,这样不会破坏双亲委派机制
    在这里插入图片描述

线程上下文类加载器

  • 利用上下文类加载器加载类,比如JDBC和JNDI等
  • JDBC中使用了DriverManager来管理项目中引入的不同数据库的驱动,比如mysql驱动、oracle驱动。
    在这里插入图片描述
  1. DriverManager类位于rt.jar包中,由启动类加载器加载
    在这里插入图片描述

  2. 依赖中的mysql驱动对应的类,由应用程序类加载器来加载。
    在这里插入图片描述

  • DriverManager属于rt.jar是启动类加载器加载的。而用户jar包中的驱动需要由应用类加载器加载,这就违反了双亲委派机制
    在这里插入图片描述
  • DriverManage使用SPI机制,最终加载jar包中对应的驱动类
    在这里插入图片描述
  • SPI中获取到应用程序类加载器
    • SPI中使用了线程上下文中保存的类加载器进行类的加载,这个类加载器一般是应用程序类加载器
      在这里插入图片描述

案例梳理

⚫1. 启动类加载器加载DriverManager。
⚫ 2. 在初始化DriverManager时,通过SPI机制加载jar包中的myql驱动。
⚫ 3. SPI中利用了线程上下文类加载器(应用程序类加载器)去加载类并创建对象。

  • 由启动类加载器加载的类,委派应用程序类加载器去加载类的方式,打破了双亲委派机制
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

OSGi模块化

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

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

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

相关文章

http客户端简单demo

socket.h头文件 #pragma once #include <iostream> #include <cstring> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <string> using std::string;namespace MySocket …

KVM虚拟机迁移原理与实践

虚拟机迁移 迁移(migration)包括系统整体的迁移和某个工作负载的迁移&#xff0c;系统整体迁移是将系统上的所有软件&#xff0c;包括操作系统&#xff0c;完全复制到另一台物理硬件机器上&#xff0c;而工作负载迁移仅仅迁移特定的工作负载。 虚拟化技术的出现&#xff0c;丰…

android源码添加adb host支持

本文开始参考在 android 上使用 adb client-CSDN博客&#xff0c;在shell中已经可以使用。但当我想在app中用 String command "/data/local/tmp/adb -s 307ef90dc8128844 shell ls";StringBuilder output new StringBuilder();try {Process process Runtime.getR…

Linux学习第二枪(yum,vim,g++/gcc,makefile的使用)

前言&#xff1a;在我的上一篇Linux博客我已经讲了基础指令和权限&#xff0c;现在我们来学习如何在Linux上运行和执行代码 目录 一&#xff0c;yum 二&#xff0c;vim 1&#xff09;命令行模式 2&#xff09;插入模式 3&#xff09;底行模式 三&#xff0c;gcc/g 四&a…

MATLAB的编程与应用,匿名函数、嵌套函数、蒙特卡洛法的掌握与使用

目录 1.匿名函数 1.1.匿名函数的定义与分类 1.2.匿名函数在积分和优化中应用 2.嵌套函数 2.1.嵌套函数的定义与分类 2.2.嵌套函数彼此调用关系 2.3.嵌套函数在积分和微分中应用 3.微分和积分 4.蒙特卡洛法 4.1.圆周率的模拟 4.2.计算N重积分&#xff08;均匀分布&am…

PHP·解决http_build_query模拟浏览器请求多选参数加下标索引的BUG| 无法模拟浏览器多选参数问题

$form_params array(id > 1,ids > [1,2,3], ); $form_params http_build_query($form_params); $form_params preg_replace(/%5B[0-9]%5D/simU, %5B%5D, $form_params);参考 http_build_query — 生成 URL-encode 之后的请求字符串

计算机提示找不到xinput1_3.dll怎么办?6个xinput1_3.dll丢失完美解决方案分享

xinput1_3.dll是Windows操作系统中的一个重要动态链接库文件&#xff0c;它负责处理游戏控制器和其他输入设备的相关功能。当计算机出现xinput1_3.dll缺失的问题时&#xff0c;可能会导致无法正常使用游戏控制器或其他输入设备。下面是针对这个问题的6个解决方法&#xff1a; 方…

基于html+jquery开发的科学计算器(课程作业)

基于html和jquery开发的科学计算器&#xff0c;该科学计算器可进行乘方、开方、指数、对数、三角函数、统计等方面的运算&#xff0c;又称函数计算器。 科学型带有所有普通的函数&#xff0c;所有的函数都分布在键盘上以致于你可以不用通过菜单列表来使用它们。 科学计算器支持…

微服务-我对Spring Clound的理解

官网&#xff1a;https://spring.io/projects/spring-cloud 官方说法&#xff1a;Spring Cloud 为开发人员提供了快速构建分布式系统中一些常见模式的工具&#xff08;例如配置管理、服务发现、熔断器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话…

常用布局以及其优缺点

当涉及到设计和排版时&#xff0c;有许多不同的布局方式可供选择。以下是几种常见的布局方式以及它们的优缺点&#xff1a; 流式布局&#xff08;Fluid Layout&#xff09;&#xff1a; 优点&#xff1a;能够根据屏幕大小自动调整内容&#xff0c;适应不同设备。灵活性高&#…

android:scaleType属性

1. matrix : 不改变原图大小&#xff0c;在ImageView左上角开始显示&#xff0c;超出部分剪裁。 2. center : 不改变原图大小&#xff0c;在ImageView中央显示&#xff0c;超出部分剪裁。 3. centerCrop(剪裁) : 原图按等比例缩放&#xff0c;直至填满整个ImageView&#xff…

分布式搜索引擎ES

文章目录 初识elasticsearch了解ES倒排索引正向索引倒排索引正向和倒排 es的一些概念文档和字段索引和映射mysql与elasticsearch 安装ES部署kibana安装IK分词器扩展词词典停用词词典 索引库操作mapping映射属性索引库的CRUD创建索引库和映射查询索引库修改索引库删除索引库 文档…

微机原理5

一、单项选择题(本大题共15小题,每小题3分,共45分。在每小题给出的四个备选项中,选出一个正确的答案。&#xff09; 下列数中最小的数是&#xff08;&#xff09; A. (10111) B. (30) C. (100010) BCD D. 17H 2,下面四个寄存器中,不能作为间接寻址的寄存器是() A. BX B. DX C.…

ChatGPT 如何改变科研之路

《Nature》全球博士后调查[1]中约有三分之一的受访者正在使用人工智能聊天机器人来帮助完善文本、生成或编辑代码、整理其领域的文献等等。 来自巴西的 Rafael Bretas 在日本生活了十多年&#xff0c;日语说得很好。书面日语的各个方面&#xff0c;例如严格的礼貌等级制度&…

【Linux基础IO篇】用户缓冲区、文件系统、以及软硬链接

【Linux基础IO篇】用户缓冲区、文件系统、以及软硬链接 目录 【Linux基础IO篇】用户缓冲区、文件系统、以及软硬链接深入理解用户缓冲区缓冲区刷新问题缓冲区存在的意义 File模拟实现C语言中文件标准库 文件系统认识磁盘对目录的理解 软硬链接软硬链接的删除文件的三个时间 作者…

2023.11.11 hive中的内外部表的区别

一.内部表操作 ------------------------------1内部---------------------------- --建库 create database hive2; --用库 use hive2; --删表 drop table t1; --建表 create table if not exists t1(id int,name string,gender string ); --复制内部表 --复制表结构:CREATE T…

计算机视觉中目标检测的数据预处理

本文涵盖了在解决计算机视觉中的目标检测问题时&#xff0c;对图像数据执行的预处理步骤。 首先&#xff0c;让我们从计算机视觉中为目标检测选择正确的数据开始。在选择计算机视觉中的目标检测最佳图像时&#xff0c;您需要选择那些在训练强大且准确的模型方面提供最大价值的图…

SpringCloud微服务:Eureka

目录 提供者与消费者 服务调用关系 eureka的作用 在Eureka架构中&#xff0c;微服务角色有两类 Eureka服务 提供者与消费者 服务提供者:一次业务中&#xff0c;被其它微服务调用的服务。(提供接口给其它微服务)服务消费者:一次业务中&#xff0c;调用其它微服务的服务。(调…

C++:容器list的介绍及使用

目录 1.list的介绍及使用 1.1 list的介绍 1.2 list的使用 1.2.1 list的构造 1.2.2 list iterator 的使用 1.2.3 list capacity 容量 1.2.4 list element access 访问list元素 1.2.5 list modifiers 修改 1.2.6 迭代器失效 1.list的介绍及使用 1.1 list的介绍 C官网 …

基于ubuntu 22, jdk 8x64搭建图数据库环境 hugegraph--google镜像chatgpt

基于ubuntu 22, jdk 8x64搭建图数据库环境 hugegraph download 环境 uname -a #Linux whiltez 5.15.0-46-generic #49-Ubuntu SMP Thu Aug 4 18:03:25 UTC 2022 x86_64 x86_64 x86_64 GNU/Linuxwhich javac #/adoptopen-jdk8u332-b09/bin/javac which java #/adoptopen-jdk8u33…