【java 基础】闲话 ClassLoader 和 SPI (一)

文章目录

    • 引子
    • 双亲委派模型
      • 你真的明白了吗?
    • 双亲委派“不够用了”
      • SPI机制
    • 其他琐碎

引子

有别于 java 提供的 IO 模块,java 中的classloader主要是用来加载类的,当然除了加载类,也可以加载资源文件。

那么首先我们会问一个问题,有了 IO 为什么要 classloader?这是我们开启 classloader 大门要弄明白的第一个问题。

java IO 提供了一些常见的功能,比如读文件、写文件,操作字符流、字节流,网络的读写,文件系统操作等等功能,不胜枚举。显而易见,java IO 提供了一些通用方法。

而 classloader 是 JVM 用来按需动态加载资源的工具。之所以有 classloader 有多方面的考虑,首先要解决程序运行时怎么加载类,需要一套机制,这套机制就是我们常说的双亲委派模型。其次是怎么读取资源,比如我们想要读取某个配置文件,或者一张图片(当然读取资源文件我们可以直接用 IO 也不是不可以,殊途同归)。

双亲委派模型

老生常谈的话题,不过也值得讨论一番。java 内建的classloader主要分为 3 类:

  • Bootstrap ClassLoader
  • Extension ClassLoader(又叫 Platform ClassLoader)
  • Application ClassLoader(又叫 System ClassLoader)

Bootstrap ClassLoader: 是最顶层的ClassLoader,负责加载JRE核心库,它是用C++实现的,无法通过Java代码来创建。
Extension ClassLoader:负责加载Java的扩展库。(本质上还是 java 官方提供的,由 java 实现的类库)
Application ClassLoader:负责加载用户类路径下的类。比如我们自己编写的类,引入的第三方 jar 包等。

如下图:我们举一个例子,假设 JVM 要加载类 A,首先会通过 Application ClassLoader 进行加载,这时首先检查其缓存中是否已加载此类,如果加载,则返回。如果缓存中没有类 A,则委托给 Extension ClassLoader进行加载,同样是先检查是否有缓存,如果没有则委托给 Bootstrap ClassLoader 进行加载,同样是检查缓存,如果还是没有,则尝试扫描 JRE 核心库是否有该类,如果有,则加载类,否则返回到 Extension ClassLoader,Extension ClassLoader 扫描其负责的扩展库,如果有,则加载,否则返回到 Application ClassLoader进行加载,Application ClassLoader扫描用户的类路径,如果找到该类,则加载,否则则抛出ClassNotFound 异常。
Image: https://uploader.shimo.im/f/XticuP44pZvBeor5.png!thumbnail?accessToken=eyJhbGciOiJIUzI1NiIsImtpZCI6ImRlZmF1bHQiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE3MDkyNzg0NzUsImZpbGVHVUlEIjoiNXhrR29HeEVqT0N6MXprWCIsImlhdCI6MTcwOTI3ODE3NSwiaXNzIjoidXBsb2FkZXJfYWNjZXNzX3Jlc291cmNlIiwidXNlcklkIjo5NDQ4NDE4fQ.7teiXi8UKNQMlxXtA9Puy-Q_HJAeV0kRoqqgjO3qs8k

你真的明白了吗?

回答下面这个问题:如果类 A 是 Extension ClassLoader 加载,而类 A 中又引入了类 B,那么类 B 会怎么被加载呢?还是从 Appcation ClassLoader 开始加载吗?

答案是否定的,类 B 会从 Extension ClassLoader 开始加载,先委托Bootstrap ClassLoader,如果没找到,则 Extension ClassLoader自己开始加载,如果找不到,则抛出 ClassNotFound,并不会再返回到 Application ClassLoader 进行加载。为什么要这样设计?很简单,留给大家自己思考吧。

双亲委派“不够用了”

有时候默认的双亲委派不够用,举个例子,java 定义了一个数据库标准接口 JDBC,各个数据库厂商会实现这个标准接口,即我们所说的数据库驱动包。大家在学JDBC 的时候应该都写过类似这种代码

Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbName");

大家可以尝试将第一句删除掉,你会发现还是可以获取到Connection,这是为什么呢?DriverManager的包名是 java.sql,显然是 jdk的核心包,所以定然不会在其中写入加载某个具体驱动类的代码。所以 java 的开发人员就发明了一种新的方法:SPI(Service Provider Interface)

SPI机制

SPI 的机制很简单,我们还是以数据库驱动为例,首先各个驱动厂商开发对应的驱动包,不过动包会有些特殊,如下图:
在这里插入图片描述
在驱动包的 META-INF/services 下会包含与所要实现驱动名称相同的一个文本文件,文本文件的内容是实现这个驱动的具体类。

然后在执行 DriverManager.getConnection("jdbc:mysql://localhost:3306/dbName");时有以下代码:
Image: https://uploader.shimo.im/f/j7jalpGRyOGJ0Ghs.png!thumbnail?accessToken=eyJhbGciOiJIUzI1NiIsImtpZCI6ImRlZmF1bHQiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE3MDkyNzg0NzUsImZpbGVHVUlEIjoiNXhrR29HeEVqT0N6MXprWCIsImlhdCI6MTcwOTI3ODE3NSwiaXNzIjoidXBsb2FkZXJfYWNjZXNzX3Jlc291cmNlIiwidXNlcklkIjo5NDQ4NDE4fQ.7teiXi8UKNQMlxXtA9Puy-Q_HJAeV0kRoqqgjO3qs8k
通过 ServiceLoader.load(Driver.class)去加载驱动。具体怎么加载这里就不说了,无非是扫描上面我们说的META-INF/services目录下的文件,将所有实现了Driver接口的驱动都注册进来。那为什么这里就可以加载到了呢?因为我们在执行ServiceLoader.load(Driver.class)方法时,方法内部是通过 Application ClassLoader 进行加载的,自然可以加载到外部的驱动包了。

那么,如果我引入了多个驱动包呢?系统怎么知道我们用的哪一个?如下图,在 Driver 接口中定义了一个方法:acceptsURL,通过对jdbc:mysql://localhost:3306/dbName这种格式的判断来决定此驱动是不是用户想要的驱动。

在这里插入图片描述
DriverManager 中调用上面实现的acceptsURL 方法:
在这里插入图片描述

其他琐碎

说了那么多,好像跟我们自己平常开发没有多少关系。其实我们也可以利用ClassLoader来加载起源,比如我们想读取一个配置文件。可以用类似ClassLoader.findResource("xxx")或者this.class.getResource("xx")。在一些代码里我们还会看到:ClassLoader cl = Thread.currentThread().getContextClassLoader();这样的代码,这些是在干嘛?后续再跟大家唠唠吧。

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

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

相关文章

java基础 - 14 Java的Deque之Deque、BlockingDeque、LinkedBlockingDeque、ArrayDeque

Java 中的 Deque(双端队列)是一种具有队列和栈特性的数据结构,它允许在两端进行插入和删除操作。Deque 接口是 Java 集合框架中的一部分,它定义了双端队列的基本操作。 BlockingDeque 接口: BlockingDeque 接口是 Deq…

【UE 材质】制作加载图案(2)

在上一篇(【UE 材质】制作加载图案)基础上继续实现如下效果的加载图案 效果 步骤 1. 复制一份上一篇制作的材质并打开 2. 添加“Floor”节点向下取整 除相同的平铺数 此时的效果如下 删除如下节点 通过“Ceil”向上取整,参数“Tiling”默认…

教师招聘和事业编d类有什么区别吗

每年都有大批怀揣教育梦想的年轻人,站在职业的十字路口,对未来充满期许与疑惑。他们中的许多人都会面临这样一个问题:教师招聘和事业编D类,到底有什么区别?今天,就让我来为你揭开这两者的神秘面纱。 别被这…

ubuntu系统下大数据服务器磁盘调优测试记录

一、背景 在kvm虚拟机ubuntu操作系统大数据平台测试的过程中,遭遇了磁盘I/O性能的瓶颈,因有cpu绑核操作,故有做隔核操作验证是否是绑核影响的磁盘I/O,后又对磁盘进行透传以及挂内存盘等操作; 二、磁盘介绍 2.1 磁盘…

蓝桥杯Python B组练习——斐波那契数列

一、题目 定义 斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数…

Linux x86平台获取sys_call_table

文章目录 前言一、根据call *sys_call_table来获取二、使用dump_stack三、根据MSR_LSTAR寄存器四、使用sys_close参考资料 前言 Linux 3.10.0 – x86_64 最简单获取sys_call_table符号的方法: # cat /proc/kallsyms | grep sys_call_table ffffffff816beee0 R sy…

可视化图表:水球图,展示百分比的神器。

Hi,我是贝格前端工场的老司机,本文分享可视化图表设计的水球图设计,欢迎老铁持续关注我们。 一、水球图及其作用 水球图是一种特殊的可视化图表,它主要用于展示百分比或比例的数据,并以水球的形式进行呈现。水球图的作…

【k8s 访问控制--认证与鉴权】

1、身份认证与权限 前面我们在操作k8s的所有请求都是通过https的方式进行请求,通过REST协议操作我们的k8s接口,所以在k8s中有一套认证和鉴权的资源。 Kubenetes中提供了良好的多租户认证管理机制,如RBAC、ServiceAccount还有各种策路等。通…

集合篇之ArrayList

一、源码如何分析&#xff1f; 1.成员变量 2.构造方法 3.关键方法 一些添加的方法。 二、debug看源码 我们给出下面代码&#xff1a; public void test01() {ArrayList<Integer> list new ArrayList<>();list.add(1);for (int i 2; i < 10; i) {list.add(i…

精读《React 高阶组件》

本期精读文章是&#xff1a;React Higher Order Components in depth 1 引言 高阶组件&#xff08; higher-order component &#xff0c;HOC &#xff09;是 React 中复用组件逻辑的一种进阶技巧。它本身并不是 React 的 API&#xff0c;而是一种 React 组件的设计理念&…

【QT+QGIS跨平台编译】之五十三:【QGIS_CORE跨平台编译】—【qgssqlstatementparser.cpp生成】

文章目录 一、Bison二、生成来源三、构建过程一、Bison GNU Bison 是一个通用的解析器生成器,它可以将注释的无上下文语法转换为使用 LALR (1) 解析表的确定性 LR 或广义 LR (GLR) 解析器。Bison 还可以生成 IELR (1) 或规范 LR (1) 解析表。一旦您熟练使用 Bison,您可以使用…

2024年个人护理赛道选品风向在哪?这份赛盈分销选品攻略必看!

2024年还会卷下去吗&#xff1f;看到一位行业大佬分享的内容深有感触&#xff1a;坚定做好产品&#xff0c;不做大卖&#xff0c;就不存在卷不卷。 有人出局&#xff0c;也会有人入局&#xff0c;并且深耕领域做大做强。 专注口腔护理的Bitvae入行不到两年&#xff0c;凭借一款…

C#学习(十四)——垃圾回收、析构与IDisposable

一、何为GC 数据是存储在内存中的&#xff0c;而内存又分为Stack栈内存和Heap堆内存 Stack栈内存Heap堆内存速度快、效率高结构复杂类型、大小有限制对象只能保存简单的数据引用数据类型基础数据类型、值类型- 举个例子 var c new Customer{id: 123,name: "Jack"…

微信小程序手势冲突?不存在的!

原生的应用经常会有页面嵌套列表&#xff0c;滚动列表能够改变列表大小&#xff0c;然后还能支持列表内下拉刷新等功能。看了很多的小程序好像都没有这个功能&#xff0c;难道这个算是原生独享的吗&#xff0c;难道是由于手势冲突无法实现吗&#xff0c;冷静的思考了一下&#…

【InternLM 实战营笔记】XTuner 大模型单卡低成本微调实战

XTuner概述 一个大语言模型微调工具箱。由 MMRazor 和 MMDeploy 联合开发。 支持的开源LLM (2023.11.01) InternLM Llama&#xff0c;Llama2 ChatGLM2&#xff0c;ChatGLM3 Qwen Baichuan&#xff0c;Baichuan2 Zephyr 特色 傻瓜化&#xff1a; 以 配置文件 的形式封装了大…

看待事物的层与次 | DBA与架构的一次对话交流

前言 在计算机软件业生涯中,想必行内人或多或少都能感受到系统架构设计与数据库系统工程的重要性,也能够清晰地认识到在计算机软件行业中技术工程师这个职业所需要的专业素养和必备技能! 背景 通过自研的数据库监控管理工具,发现 SQL Server 数据库连接数在1-2K之间,想…

Yii2中如何使用scenario场景,使rules按不同运用进行字段验证

Yii2中如何使用scenario场景&#xff0c;使rules按不同运用进行字段验证 当创建news新闻form表单时&#xff1a; 添加新闻的时候执行create动作。 必填字段&#xff1a;title-标题&#xff0c;picture-图片&#xff0c;description-描述。 这时候在model里News.php下rules规则…

利用coze 搭建“全功能“微信客服(2)

紧跟上篇 利用coze 搭建"全功能"微信客服&#xff08;1&#xff09;&#xff0c;不知道来龙去脉自行查阅 先表扬下coze: coze 是国内少数开放平台之一&#xff0c;里面提供各种插件还可以开发工作流&#xff0c;让你可以实现多模态全功能大模型 吐槽 没有API开放接口…

2024亚马逊全球开店注册前需要准备什么?

在2023年出海四小龙SHEIN、Temu、速卖通AliExpress、TikTok Shop快速增长扩张&#xff0c;成为了中国跨境卖家“逃离亚马逊”的新选择。但是&#xff0c;跨境电商看亚马逊。当前&#xff0c;亚马逊仍然是跨境电商行业的绝对老大&#xff0c;占有将近70%成以上的业务份额。 作为…

分享fastapi低级错误

我是创建表的时候把__tablename__ 写成__table__然后一直报这个错误