白话说Java虚拟机原理系列【第三章】:类加载器详解

news2025/7/13 16:26:42

文章目录

        • jvm.dll
        • BootstrapLoader:装载系统类
        • ExtClassLoader:装载扩展类
        • AppClassLoader:装载自定义类
        • 双亲委派模型
        • 类加载器加载类的方式
        • 类加载器特性
        • 类加载器加载字节码到JVM的过程
        • 自定义/第三方类加载器
        • `类加载器加载字节码到哪?`
        • Class类对象
        • 破坏双亲委派机制:spi机制


前导说明:
本文基于《深入理解Java虚拟机》第二版和个人理解完成,
以大白话的形式期望能用大家都看懂的描述讲清楚虚拟机内幕,
后续会增加基于《深入理解Java虚拟机》第三版内容,并进行二个版本的对比

JVM基本结构图


jvm.dll

首次要执行JAVA程序就都需要启动JVM虚拟机,由java.exe负责获取JRE目录位置中的jvm.dll动态链接库,然后加载运行此库,即JVM虚拟机。

BootstrapLoader:装载系统类

  • JVM启动初始化后,第一创建的类加载器为BootstrapLoader,此由C++语言实现,加载运行后它会加载Launcher.class字节码文件,Launcher内部有ExtClassLoader、AppClassLoader两个内部类,它会先创建ExtClassLoader并将它的parent设置成null,然后再创建AppClassLoader,并将它的parent设置成ExtClassLoader。至此完成了BootstrapLoader的初始化,同时也完成了类加载器的初始化。
  • BootstrapLoader加载器负责加载JAVA安装目录中的类,即核心JAVA API对应的类。如JRE目录下的rt.jar、charsets.jar等,BootstrapLoader由C++编写实现,由于不是JAVA体系,所以JVM选择了透明化该类,所以ExtClassLoader的parent设置成了null,其实代表的就是ExtClassLoader的parent为BootstrapLoader,只不过透明化了这个C++实现的类。

ExtClassLoader:装载扩展类

负责加载JRE安装目录的"\lib\ext"目录下的类。

AppClassLoader:装载自定义类

  • 负责加载自己开发的类,就是环境变量中配置的"."点对应的目录了。其实是java.class.path对应的目录,即CLASSPATH目录
  • 默认情况下使用AppClassLoader装载应用程序中的类。

双亲委派模型

问题:有这么写类加载器,实际中我们要用哪个最合理呢?

这就要看一下他的运行机制:双亲委派机制

原理:就是如果有类加载的需求时,加载器先通过parent去尝试在对应的路径下加载,如果parent得不到类文件,再由子加载器去加载,直到加载到文件。比如一个自定义的类,加载时,先由BootstrapLoader加载,加载不到再由ExtClassLoader加载,加载不到最后才由AppClassLoader进行加载。这就是委托模型机制,分工明确,各司其职。

原因:出于安全、保护JVM考虑,比如我自己实现了一个较差的String类,如果没有此机制,那么就可以随意加载到JVM,那可能导致一些问题,有了此机制,那么String永远都是有BootstrapLoader加载,且加载的是JAVA提供的核心类库中的类。

证明:要想证明累的加载过程是不是对,只需建一个main方法,运行一下,只不过增加一个java的启动参数:设置虚拟机参数"-XX:+TraceClassLoading"来获取类加载信息,信息将会打印在控制台或log

类加载器加载类的方式

  • 隐式装载:程序运行过程中碰到new关键字,则会先装载对应的类。
  • 显示装载:通过Class.forName()等类似方法显示的调用装载。

类加载途径:虚拟机对类加载的规范很模糊,即最终加载成二进制流,但是二进制流从哪来没有规定,所以可以有如下途径获取类的字节码文件:

  • ①从zip包中获取,这就是以后jar、ear、war格式的基础
  • ②从网络中获取,典型应用就是Applet
  • ③运行时计算生成,典型应用就是动态代理技术
  • ④由其他文件生成,典型应用就是JSP,即由JSP生成对应的.class文件
  • ⑤从数据库中读取,这种场景比较少见

类加载器特性

对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。这句话表达地再简单一点就是:比较两个类是否"相等",只有在这两个类是由同一个类加载器加载的前提下才有意义,否则即使这两个类来源于同一个.class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,这两个类必定不相等。

类加载器加载字节码到JVM的过程

在这里插入图片描述
此处我们忽略“使用”和“卸载”两个过程,”使用“就是我们代码中实现的功能,卸载将会交由GC处理。

1.装载:查找和导入class字节码文件到运行时数据区的方法区。
2.链接:

检查:检查载入的class文件数据的正确性。
准备:给类的静态变量分配存储空间,存于方法区。此过程还会对(虚)方发表完成初始化。
解析:将符号引用转成直接引用,常量池解析。

3.初始化:对静态变量、静态代码块(即静态方法)执行初始化工作。
最后通过加载器创建Class类对象存于堆,并指向方法区该类的存储区域。

自定义/第三方类加载器

类加载器可以由第三方自己实现一些特殊的功能。

  • ClassLoader抽象类:类加载由此开始,会调用它的loadClass方法,查看源码可以发现双亲委派的具体实现,以及各个类加载器加载的目录对应的环境变量具体是哪个。
  • 自定义加载器:如果我们要保留双亲委派机制,那么需要继承ClassLoader类并实现findClass方法(从源码可知这个方法默认是空实现,为自定义准备的扩展方法)来加载jvm默认加载器处理范围之外的类,如果我们想更广范围的加载类,比如不让AppClassLoader生效,那么只能自己重写ClassLoader类的loadClass方法了。

类加载器加载字节码到哪?

类加载器加载字节码文件到运行时数据区的方法区中,然后再完成一系列字节码文件的解析(常量池解析等),最后会创建一个与类文件相关的对象存入堆(即类对象)并通过指针指向方法区当前类的定义(指针指的是堆中的对象头中会有一个引用指向方法区类字节码定义的位置,方法区章节会详细讲解,此处知道即可)。

Class类对象

  • 类加载器加载class文件后,最终都会创建一个Class类的对象存于堆中,用于和方法区中的class文件内容关联。
  • Class类没有public的构造方法,Class类的对象是在装载类时由JVM通过调用类装载器中的defineClass()方法自动构建的。
  • 方法区中也会保存加载当前class文件的加载器信息,因为Class类的对象是由加载器创建的,所以通过Class类对象可以得知用的哪个加载器。

破坏双亲委派机制:spi机制

上边说了,双亲委派的作用就是安全,保障jdk的类只有自己的加载器能加载,但是有些时候我们需要让我们自己提供的类被加载,该怎么办呢?

几种方法: 比如

  • 就是重写源码,这个不太可取
    就是重写类加载器的loadClass方法,以此改变类加载的方式;
  • 通过jdk提供的spi方式,我们提供自己的实现类,这样通过spi的配置,就可以成功通过双亲委派来加载到我们提供的类了。

简单介绍SPI: spi的方法就是定义自己的实现类,比如数据库驱动Driver接口的实现类,然后将实现类放到META-INF/services目录的Driver全名的配置文件中,这样就可以了,当然使用的时候要用ServiceLoader来加载具体的实现类(spi内容可以到dubbo章节的讲解中学习)。

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

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

相关文章

浅谈冯诺依曼体系,操作系统和进程概念

文章目录浅谈冯诺依曼体系结构和操作系统冯诺依曼体系结构冯诺依曼体系结构图操作系统进程task_struct内容分类进程内核数据结构(task_struct)进程对应的磁盘代码查看进程ps 列出系统中运行的进程ps ajx 查看系统中所有运行的进程ps ajx | grep 程序名 :…

【Linux操作系统】——在Ubuntu20.04上安装MySQL数据库

在Ubuntu上安装MySQL MySQL是一个开源数据库管理系统,通常作为流行的LAMP(Linux,Apache,MySQL,PHP / Python / Perl)堆栈的一部分安装。它使用关系数据库和SQL(结构化查询语言)来管…

类美团外卖、骑手、类快递取餐柜、整合菜品供应商、前厅、后厨、配送、智能厨电设备的智慧餐饮业务

一种商业模型之类美团外卖、骑手、类快递取餐柜、整合前厅、后厨、智能厨电设备智慧餐饮业务架构 涉及到: 0、基础数据管理 1、菜谱创错 2、菜谱编译 3、菜谱商业化 4、厨电管理 5、后厨管理 6、前厅管理 …

【Call for papers】SIGKDD-2023(CCF-A/数据挖掘/2023年2月2日截稿)

29TH ACM SIGKDD CONFERENCE ON KNOWLEDGE DISCOVERY AND DATA MINING. 文章目录1.会议信息2.时间节点3.论文主题1.会议信息 会议介绍: 29TH ACM SIGKDD CONFERENCE ON KNOWLEDGE DISCOVERY AND DATA MINING. 会议全称: ACM Knowledge Discovery and D…

为什么 APISIX Ingress 是比 Traefik 更好的选择?

本文可以为正在选型 Kubernetes Ingress Controller 产品的用户提供一些帮助。 作者张晋涛,API7.ai 云原生专家,Apache APISIX Committer、Kubernetes Ingress Nginx Reviewer Apache APISIX Ingress Apache APISIX Ingress 是一个使用 Apache APISIX 作…

FrameLayout布局案例

框架布局-FrameLayout 1.FrameLayout简介 1.简介:白话,墙角堆砌东西 就是开辟一个巨大的空间控件的位置不能够指定,默认就是左上角后面对挡住前面的2.属性 属性名称 对应方法 说明 android:foreground setForeground(Drawable) 设置绘制…

【408篇】C语言笔记-第十四章( 二叉树的建树和遍历考研真题实战)

文章目录第一节:冒泡排序1. 排序2. 冒泡排序第二节:冒泡排序实战1. 步骤2. 代码3. 时间复杂度与空间复杂度第三节:快速排序原理与实战1. 基本思想2. 快速排序实战3. 时间复杂度与空间复杂度第四节:插入排序原理及实战1. 插入排序原…

HSF 实现原理

HSF 实现原理 提供服务的流程 - server启动时候向ConfigServer注册 - client启动时候向ConfigServer请求list - client缓存list,发现不可用的server,从缓存中remove - ConfigServer通过心跳包维护可用server的list - list有更新的时候,…

单片机——LED

0. 单片机编程的一般步骤 目标分析:点亮开发板上的LED灯 电路原理图分析:相关器件的工作原理 数据手册分析:IO端口控制 代码编写、编译 下载与调试 1. LED简介 Led:即发光二极管,具有单向导通性,一般…

验证码、通知短信API常见使用问题

如今短信应用于我们生活工作的方方面面,注册或者登录一个应用可以用短信验证码快速登录,支付可以使用短信验证码;商家搞促销活动可以发送通知短信给客户,会员到期了商家可以发送告警短信给会员用户…可见验证码短信API和通知短信A…

JavaFX爱好者看过来,这款工具值得拥有

前言 各位CSDN的博友们,随着各地政策的放开,大伙现在是在水深火热当中呢?还是天选打工人-安然无羊。在这里,希望阳了的朋友,赶紧恢复健康,早日康复。希望没有阳的朋友们,继续坚持,万…

聊聊设计模式-解释器模式?

简介 解释器模式属于行为型模式。它是指给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。是一种按照规定的语法进行解析的模式 编译器可以将源码编译解释为机器码,让CPU能进行识别并…

C++调用matlab引擎画三维图

VS2012设置 项目–项目属性–配置属性–VC目录–包含目录 D:\MATLAB\R2016a\extern\include 项目–项目属性–配置属性–VC目录–库目录 D:\MATLAB\R2016a\extern\lib\win64\microsoft 添加依赖项有两种方法: 方法一:项目中设置 项目–项目属性–配置属…

一、线程相关概念

文章目录相关概念程序(program)进程线程单线程与多线程并发与并行相关概念 程序(program) 是为完成特定任务、用某种语言编写的一组指令的集合。简单的说:就是我们写的代码。 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程&#xff0c…

基于注解方式Spring Security忽略拦截

文章目录1.Spring Security忽略拦截配置2.基于配置文件注入2.1.添加配置2.2.修改Spring Security配置类2.3. 测试3.基于注解的方式过滤接口3.1.添加注解3.2.获取所有使用了IgnoreWebSecurity注解的接口访问路径3.3.测试1.Spring Security忽略拦截配置 关于Spring Securite的使…

SDL学习

学习笔记:整合安全开发生命周期SDL的Devops工具链建设 分享思路:《SDL安全开发生命周期介绍》 1、什么是SDL? 2、为什么需要SDL? 3、DevSecOps实践(SDLDevOps) 【整合安全开发生命周期SDL的DevOps工具链建…

408 考研《操作系统》第三章第一节:内存

文章目录教程1. 内存的基础知识1.1什么是内存?有何作用?补充知识:几个常用的数量单位2. 进程的运行原理2.1 指令的工作原理2.2 逻辑地址vs物理地址2.3 从写程序到程序运行2.4 装入模块装入内存2.5 装入的三种方式2.5.1 ——绝对装入2.5.2 ——…

VR的内容荒漠,字节救不了

文|智能相对论 作者|Kinki 去年以来,“元宇宙”概念大火,掀起了新一轮的产业布局和科技博弈,脸书Facebook更直接改名Meta,展示其看好元宇宙未来的决心,国内大厂如腾讯、字节、阿里等,也在游戏、社交、硬件…

Macos安装和卸载第三方软件的正确方法

Mac第三方软件通常指的是非MacApp Store渠道下载安装的应用程序。在Mac电脑中有很多Mac系统内置的软件,但有些用户也喜欢安装一些第三方的软件来提高工作效率,那么我们如何正确的安装和卸载第三方软件呢?教程都在下面哦~ mac第三方软件安装方…

Fabric.js 使用图片遮盖画布(前景图)

本文简介 点赞 关注 收藏 学会了 在 《Fabric.js 使用纯色遮挡画布》 中讲到使用纯色的方式遮盖画布。如果你的常见需要使用图片来遮盖的话,fabric.js 也提供了相应的属性来配置。 相比起使用纯色遮盖画布,使用图片会更复杂。 因为图片本身是有尺寸…