JVM类加载器子系统与SPI

类加载器以及SPI 目录:            申明            JVM类加载以及SPI 类的生命周期: 1.加载 2.验证 类加载器以及双亲委派模型 SPI (service provider interface) 3.准备 4.解析 5.初始化阶段 申明 本文很多的内容都是作者通过阅读《深入理解Java虚拟机[JVM高级特性与最佳实践](周志明)》这本书学习到的。如果需要关于类... 阅读详情

类加载器

JVM中有两种类型的加载器,一种是由C++编写,一种是由JAVA编写,除了启动类加载器(Bootstrap Class Loader)是由C++编写的以外,其他都是由JAVA编写的,由JAVA编写的加载器都继承与java.lang.ClassLoader,JVM还支持自定义加载器,对于自定义加载器的典型用法就是可以破坏JVM的双亲委派,为什么要破坏双亲委派,想要做到破坏双亲委派的项目必有这个需求,比如像我们的web服务器tomcat,就自定义了类加载器,不仅仅是web服务器,像目前主流的技术框架都会自定义类加载器,自定义类加载器可以加载自己想要加载的class,不仅仅是加载本地的,还可以加载来自于网络的class文件。
JVM的类加载器有:启动类加载器、扩展类加载器、应用类加载器、自定义类加载器;JVM的类加载器是属于双亲委派的模式,就是当我的类加载器需要加载一个类时,它自己不会去完成这个操作,它会把请求向上委派,直到启动类加载器去加载,如果最后都没有加载成功,也就是没有找到全限定名的class时,这时候JVM会抛出一个ClassNotFound的异常,下图为我们的类加载器的结构:
在这里插入图片描述
上图为类加载器的结构图,从图中可以看出我们要加载自己的类是向上委派给自己的父类加载器去完成的;其中最上层的启动类加载器是C++编写的,我们无法去查看它的实现,其他都是java实现的类加载器,因此,启动类加载器无法被Java程序调用
启动类加载器不像其他类加载器有实体,它是没有实体的,JVM将C++处理类加载的一套逻辑定义为启动类加载器。

启动类加载器

查看启动类加载器的加载路径

URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
for (URL urL : urLs) {
    System.out.println(urL);
}

输出:
file:/D:/tools/java8_212/jre/lib/resources.jar
file:/D:/tools/java8_212/jre/lib/rt.jar
file:/D:/tools/java8_212/jre/lib/sunrsasign.jar
file:/D:/tools/java8_212/jre/lib/jsse.jar
file:/D:/tools/java8_212/jre/lib/jce.jar
file:/D:/tools/java8_212/jre/lib/charsets.jar
file:/D:/tools/java8_212/jre/lib/jfr.jar
file:/D:/tools/java8_212/jre/classes
可以看到启动类加载器主要加载了我们的jre下的核心包

扩展类加载器

  ClassLoader classLoader = ClassLoader.getSystemClassLoader().getParent();

        URLClassLoader urlClassLoader = (URLClassLoader) classLoader;

        URL[] urls = urlClassLoader.getURLs();
        for (URL url : urls) {
            System.out.println(url);
        }

file:/D:/tools/java8_212/jre/lib/ext/access-bridge-64.jar
file:/D:/tools/java8_212/jre/lib/ext/cldrdata.jar
file:/D:/tools/java8_212/jre/lib/ext/dnsns.jar
file:/D:/tools/java8_212/jre/lib/ext/jaccess.jar
file:/D:/tools/java8_212/jre/lib/ext/jfxrt.jar
file:/D:/tools/java8_212/jre/lib/ext/localedata.jar
file:/D:/tools/java8_212/jre/lib/ext/nashorn.jar
file:/D:/tools/java8_212/jre/lib/ext/sunec.jar
file:/D:/tools/java8_212/jre/lib/ext/sunjce_provider.jar
file:/D:/tools/java8_212/jre/lib/ext/sunmscapi.jar
file:/D:/tools/java8_212/jre/lib/ext/sunpkcs11.jar
file:/D:/tools/java8_212/jre/lib/ext/zipfs.jar
加载ext扩展目录的jar

应用类加载器

默认加载用户程序的类加载器

查看类加载器加载的路径

 String[] urls = System.getProperty("java.class.path").split(":");

        for (String url : urls) {
            System.out.println(url);
        }

        System.out.println("================================");

        URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();

        URL[] urls1 = classLoader.getURLs();
        for (URL url : urls1) {
            System.out.println(url);
        }

类加载器加载的类如何存储

在这里插入图片描述
从上图可以得到不同的类加载器在加载类到方法区中过后是会在方法区开辟自己的一部分空间,也就是说不同的类加载器在加载同一个类到方法区过后,他们的内存地址是不一样的,因为在方法区中的地址不一样,而JVM的加载过程是双亲委派,为什么要双亲委派??其中的一部分原因就是为了防止我们的同一个类被不同的加载器所加载,那么它在内存中就会存在多份,所以使用双亲委派机制就可以很好避免这种情况的发生。
当我们想要得到一个类的对象的时候,需要从方法区中取得这个类,也就是类加载的过程(经过一系列的过程)然后初始化在堆区创建空间来存储我们创建的对象。

双亲委派

什么是双亲委派,双亲委派就是JVM在加载类时的一种机制,每当有类加载请求时,会把请求委托给自己的父类,让父类帮自己完成类的加载,一层一层网上委托,直到委托给启动类加载,如果最后都没有被加载,则会抛出ClassNotFound一层;下图就是双亲委派的说明:
在这里插入图片描述

打破双亲委派

因为在某些情况下父类加载器需要委托子类加载器去加载class文件。受到加载范围的限制,父类加载器无法加载到需要的文件,以Driver接口为例,由于Driver接口定义在jdk当中的,而其实现由各个数据库的服务商来提供,比如mysql的就写了MySQL Connector,那么问题就来了,DriverManager(也由jdk提供)要加载各个实现了Driver接口的实现类,然后进行管理,但是DriverManager由启动类加载器加载,只能记载JAVA_HOME的lib下文件,而其实现是由服务商提供的,由系统类加载器加载,这个时候就需要启动类加载器来委托子类来加载Driver实现,从而破坏了双亲委派。

类似这样的情况就需要打破双亲委派。

打破双亲委派的意思其实就是不委派、向下委派

SPI机制

打破双亲委派的还有一个机制是SPI机制
什么是SPI SPI ,全称为 Service Provider Interface,是一种服务发现机制

它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。
这一机制为很多框架扩展提供了可能,比如在Dubbo、JDBC中都使用到了SPI机制。我们先通过一个很简单的例子来看下它是怎么用的:

首先我创建4个工程:
xxx-core 创建一个接口PayService
xxx-dev1 创建一个测试类
xxx-dev2 创建一个微信支付类实现PayService
xxx-dev3 创建一个支付宝支付类实现PayService

如下:
xxx-core:
PayService:

public interface PayService {
    void pay();
}

xxx-dev2:
WxPayService:

public class WxPayService implements PayService {
    @Override
    public void pay() {
        System.out.println("Wxpay....");
    }
}

xxx-dev3:
AliPayService

public class AliPayService implements PayService {
    @Override
    public void pay() {
        System.out.println("AliPay....");
    }
}

我们在dev2和dev3工程的resources下面还要建立一个服务文件:
在这里插入图片描述

其中com.xxx.**.PayService就是你的实现类

我们来编写我们的测试类:
xxx-dev1:

public class SpiTest {

    public static void main(String[] args) {
        ServiceLoader<PayService> services = ServiceLoader.load(PayService.class);
        services.forEach(item ->{
            item.pay();
        });
    }
}

通过jdk提供的SPI机制ServiceLoader来实现服务的发现;
这样运行是不能输出任何东西的,但是当我们在dev1工程引入xxx-dev2就会输出Wxpay…,
当我们将dev1工程换成dev2的时候,会输出AliPay…
如果我们把dev1和dev2都引入了,那么就都会被发现,被注册,那么就会输出:
Wxpay…
AliPay…

(二)JVM类加载子系统 类加载机制、双亲委派模型 阅读详情

相关推荐

当图像配准遇见边缘计算:低功耗设备的优化实践

本文探讨了在边缘计算环境下优化图像配准技术的实践方法,重点解决低功耗设备如树莓派和Jetson Nano上的算力瓶颈问题。通过算法轻量化、硬件加速和内存优化等策略,实现了毫秒级图像配准,适用于智能安防、移动医疗等实时性要求高的场景。

weixin_29054195的博客 386

【JVM】Java中SPI机制

中提到SPI和JDBC相关内容,那么是如何打破双亲委派模型呢?本文进行一个讲解,在开始讲解之前,我们需要先了解Java中的SPI机制。

weixin_44078354的博客 1258

解决RK3566 USB OTG模式识别问题:从原理图分析到otg_mode文件操作全解析

本文深入解析RK3566 USB OTG模式识别问题,从硬件原理图设计到Linux内核的otg_mode文件操作,提供全面的调试方案。针对USB_OTG0_ID引脚电路设计、电源管理关联及内核驱动交互等关键点,给出实战调试技巧和常见问题解决方案,帮助开发者高效解决USB OTG模式切换难题。

eee77的博客 865

jvm-sanbox详解-SPI机制

什么是SPI机制 SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的接口。我们知道JDK代码提供了大量的方便的工具类给我们使用,JDK会对经常使用接口进行抽象统一。如链接数据库我们可以使用java.sql.DriverManager,但各种数据库的实现各自不同,所以为了给用户统一使用,屏蔽底层各自难懂的细节,我们这种SPI机制产生了。 mysql加载驱动 回想我们经常使用mysql的过程 0.配置文件: url: jdbc:mysql://

xyznol的博客 632

oscp备考,oscp系列——Djinn3靶场:ssti漏洞,pkexec提权

oscp备考,oscp系列——Djinn3靶场:ssti漏洞,pkexec提权难度简单偏上对于低权限shell获取涉及:ssti漏洞对于提权:pkexec提权。

2202_75361164的博客 633

量化策略分享之ST股弱转强,回测年化123%

本策略的核心是精选ST股票,国九条过滤,防止直接暴雷退市,只做ST股票的弱转强,弱转强的认定标准是前日涨停但昨日不涨停,昨日收盘价大于前一日最低价,昨日收盘价大于10日线,昨日成交量大于前一日的成交量但小于前一日成交量的10倍,股价大于1;这类股票强势,有资金介入,能获得超额收益。

qq_29301281的博客 1268

JVM与SpringBoot SPI机制深度解析

在开发过程中,我们常常会遇到需要扩展或定制化框架功能的需求。以SpringBoot为例,它作为一个流行的Java应用框架,提供了丰富的扩展点。SPI(Service Provider Interface)机制正是SpringBoot实现扩展性的关键之一。下面,让我们通过一个具体的场景来引出SPI机制的重要性。场景描述:假设我们正在开发一个基于SpringBoot的微服务架构,其中涉及到日志记录功能。为了满足不同业务场景的需求,我们希望能够根据不同的环境(如开发、测试、生产)选择不同的日志记录策略。

JavaCodePro的博客 1056

rk3568 rk628桥片hdmi转lvds

RK628 是瑞芯微全新推出的视频桥接芯片,支持丰富的显示接口,支持高分辨率大屏产品转换需求。基于DRM、FB的显示框架易于使用。 输入信号支持:HDMI、RGB、BT.1120,输出信号支持 HDMI、GVI、Dual LVDS、Dual MIPI、MIPI-CSI、RGB、BT.1120,最高支持4K 60fps 输入/输出转换,并且支持输入到输出 1/4~4倍的缩放。

weixin_35723192的博客 1131

通俗易懂的解释 Java 中的 SPI 机制

深入浅出的讲解 Java 中的 SPI 机制

owoaa的博客 1617

数据库系统工程师软考备战:第三篇 - SQL语言深入解析与应用

​​创建表​​​修改表​​​删除表​。

Programming Talk 121

AI智能体面试实战与真题解析: 312+道面试题完整答案 (下篇)

本文覆盖220道基础八股文+92道项目面试题,涵盖Agent架构、RAG、工具调用、记忆系统、多智能体、大模型基础、工程化实践、Prompt工程9大模块,含完整代码实现和模拟面试剧本。

program哲学 296

JVM类加载机制、双亲委派和SPI机制

当编译器将 Java 源码编译为字节码之后,虚拟机便可以将字节码读取进内存,从而进行解析、运行等整个过程。我们将这个过程称为 Java 虚拟机的「类加载机制」。「类加载机制」中,通过类加载器()来完成类加载的过程。JVM 中,类加载器默认使用双亲委派原则。双亲委派机制是一种任务委派模式,是 Java 中通过加载工具()加载类文件的一种具体方式。具体表现为服务提供接口(SPI,

mfmfmfo的博客 1215

dify制作的工作流如何通过API调用

本文介绍了如何通过Python程序调用Dify工作流API实现数据处理功能。文章详细展示了workflow和chatflow的调用方法,包括参数设置和结果输出,并提供了一个完整的API调用工具代码示例。该工具可实现文本处理、成果查重、关键词生成等功能,支持通过Python脚本或Postman进行调用。核心代码包含API请求函数和批量处理函数,通过HTTP请求与Dify服务端交互,实现自动化数据处理流程。

hhue2007的专栏 933

JVM一之类加载子系统

作用:JVM自带的三个加载器只能加载指定路径下的类字节码,如果某些情况下,我们需要加载应用程序之外的类文件呢?就需要用到自定义类加载器,就像是在汽车行驶的时候,为汽车更换轮子。比如本地D盘下的,或者去加载网络上的某个类文件,这种情况就可以使用自定义加载器了。

蜗牛跑的快 1395

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

02 jvm类加载子系统

jvm类加载子系统JVM细节版架构图类加载子系统作用类加载子系统功能细分加载模块链接模块分为三块,即验证、准备、解析验证准备解析初始化模块类加载器分类 JVM细节版架构图 类加载子系统作用 类加载子系统负责从文件系统或者网络中加载class文件,class文件在文件开头有特定的文件标识即16进制CA FE BA BE; 加载后的Class类信息存放于一块成为方法区的内存空间。除了类信息之外,方法区还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的

Bamboou的博客 229

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

JVM 类加载子系统

类加载子系统

qianqia_n的博客 1267

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

JVM类加载子系统、类加载机制

自定义类加载器需继承;核心重写方法(而非),避免破坏双亲委派机制;步骤:重写→ 读取字节码 → 调用将字节码转为Class对象。包含双亲委派的核心逻辑,重写会破坏该机制)双亲委派机制是类加载子系统遵循的核心规则,本质是“逐级委托、自下而上检查、自上而下加载首先检查该类是否已被加载,如果是则直接返回。如果没有,则委托给父类加载器去加载(递归调用)。如果所有父类加载器都无法加载(在自己的搜索范围内找不到类),则由当前类加载器尝试加载。fill:#333;important;

m0_64616651的博客 886

JVM -- 类加载子系统

类加载子系统

neei的博客 432

jvm类加载器,类加载机制详解

前言 今天我们来讲讲jvm里类加载的过程,我们写了那么多类,却不知道类的加载过程,岂不是很尴尬。 jvm的启动是通过引导类加载器(bootstrap class loader)创建一个初始类(initial class)来完成的,这个类是由jvm的具体实现指定的。[来自官方规范] jvm组成结构之一就是类装载器子系统,我们今天就来仔细讲讲这个组件。 Java代码执行流程图 大家通过这个流程图,了解一下我们写好的Java代码是如何执行的,其中要经历类加载器这个流程,我们就来仔细讲讲这里面的知识点。

跨链技术践行者 518

JVM类加载子系统

继承 java.lang.ClassLoader 类。

weixin_47593207的博客 554

类加载子系统

本文摘要: Java类加载过程分为加载、链接和初始化三个阶段。加载阶段读取.class文件生成Class对象;链接阶段包括验证、准备和解析;初始化阶段执行静态代码块。类加载可通过多种途径触发,但加载不一定导致初始化,如访问static final编译期常量不会初始化类。JVM采用双亲委派机制,通过启动类、扩展类和应用程序类加载器的层级结构确保类安全加载。自定义类加载器需继承ClassLoader并重写findClass方法。双亲委派机制通过责任链模式实现,避免重复加载并保证核心类安全。

weixin_42022364的博客 993

尚硅谷-宋红康-jvm版学习笔记之 类加载子系统

一.JVM简介 1.JVM的作用 java虚拟机就是二进制字节码的运行环境,负责装载字节码,解释或者编译为对应平台上的机器指令执行。 2.JVM的特点 一次编译,到处运行 自动内存管理 自动垃圾回收 3.JVM的位置 4.JVM的架构模型 5.JVM的生命周期 二.类加载子系统 1.jvm的内存结构 包含三部分 a.类加载子系统 ...

qq_34748451的博客 498

JVM类加载机制详解——类加载器

一、什么是类加载器? 在上篇JVM类加载机制详解——类加载过程,介绍了类的加载过程,在类的加载过程中的第一个阶段是“加载”(Loading)阶段,“加载”的一个很重要的前提便是通过一个类的全限定名来获取该类的字节码,而这个获取类字节码的动作就是类加载器所要干的事。 二、类加载器种类 Java虚拟机中有3种类加载器,它们分别是启动类加载器(Bootstrap Class Loader)、扩展类加载器(Extension Class Loader)和应用类加载器(Application Class .

jb84006的博客 920

JVM虚拟机系统性学习-类加载子系统

是 Javac 编译器自动生成的,该方法由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并生成的,如果一个类中没有静态代码块, 也没有变量赋值的动作,那么编译器可以不为这个类生成。这里不包含用 final 修饰的 static 变量,因为 final 修饰的变量在编译为 class 字节码文件的时候就会分配了,准备阶段会显式初始化。验证:目的在于确保 class 文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性。加载类的class文件时,Java虚拟机采用的是。

qq_45260619的博客 1075

JVM类加载器

文章目录一、类加载器二、类与类加载器三、双亲委派模型四、破坏双亲委派模型4.1、Tomcat4.1.1、WebApp类加载器4.1.2、Shared类加载器4.1.3、Catalina类加载器4.1.4、Common类加载器4.1.5、Jsp类加载器4.2、JDBC 一、类加载器 从Java虚拟机的角度来讲,只存在两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),这个类加载器使用C++语言实现,是虚拟机自身的一部分;另一种就是所有其他的类加载器,这些类加载器都由Java语

rockvine的博客 3485
上一篇: JVM底层之类加载器
下一篇: 手动解析java字节码文件
Life  journey
博客等级 码龄17年 1万+粉丝 80原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值