当前位置: 首页 > news >正文

详解JAVA类加载器

目录

1.概述

2.双亲委派

3.ServiceClassLoader

4.URLClassLoader

5.加载冲突


1.概述

概念:

类加载器(Class Loader)是Java虚拟机(JVM)的一个重要组件,负责加载Java类到内存中并使其可以被JVM执行。类加载器是Java程序的核心机制之一。

分类:

类加载器一共有三种:

  • 启动类加载器,加载系统类rt.jar。
  • 扩展类加载器,加载JDK内部,rt.jar之外,由于JDK版本迭代而新出现的扩展类。
  • 应用类加载器加载J用户所配置的classpath下的类。

三种类加载器之间从上到下有父子关系,上层是下层的父加载器。

2.双亲委派

在类加载中可能会遇见这样一种情况:

JDK里自带一个java.lang.String,有一个恶意的攻击类也将类的全类名命名为java.lang.String。如果我们想使用String类型的时候,类加载器将这个伪装成JDK的String类的恶意类加载执行,系统就将遭受到破坏。

很明显,为了安全起见JDK需要一种合理的加载方式来控制类的加载,这种合理的加载方式就是——双亲委派机制。

双亲委派机制总结起来就是:

先找父级加载器要,要是父级加载器没有,再由自己加载。

因为启动类加载器、扩展类加载器工作在应用的启动阶段,加载的也是JDK内核相关的jar,与应用没有太大关系,与应用相关的只有应用程序加载类,而应用程序的父级最多也就是扩展类加载器、启动类加载器,也就是最多找两个双亲拿,所以称为双亲委派机制。

整个类加载的详细流程为:

我们来看看任意一个ClassLoader的loadClass源码,整个源码中双亲委派的体现很直接:

类加载器在需要加载一个类(class)的时候会先判断类是否被自己加载过,

如果没有,调用其成员变量classloader parent委托其父载器帮忙加载,

父加载器再重复以上过程,如果递归到最顶级的启动类加载器,发现都加载不了,

当前启动器会自行加载。

3.ServiceClassLoader

SPI机制:

SPI(Service Provider Interface),是在JDK1.6中提出的一种基于接口的服务发现机制,它允许第三方服务提供者扩展框架的功能。在SPI机制中,框架定义一组接口,并规定这些接口的实现类必须以一定的命名规则放在特定的路径下,然后通过Java自带的SPI机制,动态地加载和实例化这些实现类。

基于SPI机制可以实现这样的生态结构,由官方制定一些标准,厂商去给出实现,也就是官方给出接口,由各大厂商去实现接口,如JAVA EE规范中的JDBC规范等等,支撑SPI实现的核心是一个类加载器——ServiceClassLoader。

ServiceClassLoader是一种用于加载和实例化服务提供者的工具类。服务提供者是指实现了特定接口或抽象类的类,而服务加载器则负责在运行时动态地查找和加载这些实现类。

  • 定义服务接口:定义一个Java接口或抽象类,用于描述服务提供者必须实现的行为。

  • 实现服务提供者:定义一个或多个服务提供者,实现服务接口或抽象类。

  • 配置服务提供者:在META-INF/services目录下创建一个以服务接口或抽象类名为文件名的文件,并在文件中列出所有实现服务接口或抽象类的类名。

  • 加载服务提供者:使用Service Loader类动态加载和实例化服务提供者。

代码示例:

接口:

package com.eryi;public interface HelloService {void sayHello();
}

实现类:

package com.eryi;public class ChineseHelloService implements HelloService{@Overridepublic void sayHello() {System.out.println("你好!");}
}
package com.eryi;public class EnglishHelloService implements HelloService{@Overridepublic void sayHello() {System.out.println("Hello!");}
}

发布服务:

在META-INF/services目录下创建一个名为"com.eryi.HelloService"的文件,文件内容如下:

com.eryi.EnglishHelloService
com.eryi.ChineseHelloService

服务发现:

package com.eryi;import java.util.ServiceLoader;public class test {public static void main(String[] args) {ServiceLoader<HelloService> loader = ServiceLoader.load(HelloService.class);for (HelloService service : loader) {service.sayHello();}}
}

运行结果:

4.URLClassLoader

启动类加载器、扩展类加载器、应用类加载器均是在程序工作之前完成对各个路径下所有jar包的加载的,这些路径里的jar包后续如果有什么变化,这三个类加载器是无法进行加载从而动态进行更新的。URLClassLoader就是为了实现这种动态加载而出现的。

URLClassLoader支持三种路径:

  • 目录

  • jar包

  • 网络

代码示例:

public class test {public static void main(String[] args) throws Exception {// 创建一个URLClassLoader,指定加载路径为当前目录URLClassLoader classLoader = new URLClassLoader(new URL[] { new URL("file:./") });// 动态加载HelloWorld类Class<?> helloWorldClass = classLoader.loadClass("HelloWorld");// 创建HelloWorld对象Object helloWorld = helloWorldClass.newInstance();// 调用HelloWorld对象的sayHello方法helloWorldClass.getMethod("sayHello").invoke(helloWorld);}
}class HelloWorld {public void sayHello() {System.out.println("Hello, world!");}
}

由于URLClassLoader具有动态加载的特性,所以很适合拿来做热部署。

5.加载冲突

同一个类被不同加载器加载,加载结果视为两个不同类。

所以在加载之前需要判断是否被加载,如果未加载,则遵循双亲委托模型,从而避免加载冲突。

代码示例:

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;public class Main {public static void main(String[] args) throws Exception {// 创建两个不同的URLClassLoader,分别加载同一个类URL[] classpath = { new File("classes/").toURI().toURL() };URLClassLoader classLoader1 = new URLClassLoader(classpath);URLClassLoader classLoader2 = new URLClassLoader(classpath);// 使用classLoader1加载HelloWorld类Class<?> helloWorldClass1 = classLoader1.loadClass("HelloWorld");// 使用classLoader2加载HelloWorld类Class<?> helloWorldClass2 = classLoader2.loadClass("HelloWorld");// 输出两个类是否相同System.out.println(helloWorldClass1 == helloWorldClass2); // false}
}class HelloWorld {public void sayHello() {System.out.println("Hello, world!");}
}

相关文章:

详解JAVA类加载器

目录 1.概述 2.双亲委派 3.ServiceClassLoader 4.URLClassLoader 5.加载冲突 1.概述 概念&#xff1a; 类加载器&#xff08;Class Loader&#xff09;是Java虚拟机&#xff08;JVM&#xff09;的一个重要组件&#xff0c;负责加载Java类到内存中并使其可以被JVM执行。类…...

记录一些常用C标准库函数,以及Linux系统调用函数的作用(不断更新)

C标准库函数 perror() 函数 作用&#xff1a;perror函数是C标准库中的一种函数&#xff0c;用于在STDERR&#xff08;标准错误输出流&#xff09;中输出给定的错误信息字符串。它不属于Linux系统调用函数。 具体使用方法&#xff1a;perror("调用的函数名") 所需…...

RK3568平台开发系列讲解(显示篇)DRM的atomic接口

🚀返回专栏总目录 文章目录 一、Property二、Standard Properties三、代码案例沉淀、分享、成长,让自己和他人都能有所收获!😄 📢目前DRM主要推荐使用的是 Atomic(原子的) 接口。 一、Property Property(属性)—– Atomic操作必须依赖的基本元素 Property把前面的…...

2022年MathorCup数学建模C题自动泊车问题解题全过程文档加程序

2022年第十二届MathorCup高校数学建模 C题 自动泊车问题 原题再现 自动泊车是自动驾驶技术中落地最多的场景之一&#xff0c;自动泊车指在停车场内实现汽车的自动泊车入位过程&#xff0c;在停车空间有限的大城市&#xff0c;是一个比较实用的功能&#xff0c;减少了驾驶员将…...

【需求响应】基于数据驱动的需求响应优化及预测研究(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…...

Bellman-ford和SPFA算法

目录 一、前言 二、Bellman-ford算法 1、算法思想 2、算法复杂度 3、判断负圈 4、出差&#xff08;2022第十三届国赛&#xff0c;lanqiaoOJ题号2194&#xff09; 三、SPFA算法&#xff1a;改进的Bellman-Ford 1、随机数据下的最短路问题&#xff08;lanqiaoOJ题号1366&…...

假如你知道这样的MySQL

数据库三范式是什么? 第一范式&#xff08;1NF&#xff09;&#xff1a;字段具有原子性,不可再分。(所有关系型数据库系 统都满足第一范式数据库表中的字段都是单一属性的&#xff0c;不可再分)第二范式&#xff08;2NF&#xff09;是在第一范式&#xff08;1NF&#xff09;的…...

SpringBoot笔记(一)入门使用

一、为什么用SpringBootSpringBoot优点创建独立Spring应用内嵌web服务器自动starter依赖&#xff0c;简化构建配置自动配置Spring以及第三方功能提供生产级别的监控、健康检查及外部化配置无代码生成、无需编写XMLSpringBoot缺点人称版本帝&#xff0c;迭代快&#xff0c;需要时…...

C++20 协程体验

1 介绍协程是比线程更加轻量级并发编程方式&#xff0c;CPU资源在用户态进行切换,CPU切换信息在用户态保存。协程完成异步的调用流程&#xff0c;并对用户展示出同步的使用方式。协程的调度由应用层决定&#xff0c;所以不同的实现会有不同的调度方式&#xff0c;调度策略比较灵…...

这三个小事你做HIGG FEM时要知道

【这三个小事你做HIGG FEM时要知道】1.为什么做了Higg FEM 自评后要做验证&#xff1f;「自评 验证」Higg FEM 是一个持续改善的框架方法&#xff0c;来帮助工厂实现持续的环保改善&#xff0c;是一个最基本的要求&#xff0c;如果工厂期望得到一个更加客观的评价&#xff0c;…...

.net6 wpf程序一个内存不断增长问题的解决方法

一个.net6的应用程序&#xff0c;底层不断采集数据。使用wpf制作了一个简单的界面显示数据接收的情况。程序中引用了 Material Design UI框架。当程序长时间运行时发现内存在不断增长。一个星期后工作集占用内存达到1GB。使用dotnet-dump工具收集内存使用情况&#xff0c;并且分…...

NICEGUI---ROS开发之中常用的GUI工具

0. 简介 对于ROS来说&#xff0c;如果不具备一定知识的人员来使用这些我们写的算法&#xff0c;如果说没有交互&#xff0c;这会让用户使用困难&#xff0c;所以我们需要使用GUI来完成友善的数据交互&#xff0c;传统的GUI方法一般有PYQT这类GUI方法&#xff0c;但是这类GUI工…...

高盐废水除钙镁的技术解析

高盐废水指含有机物和至少总溶解固体(totaldissolvedsolids&#xff0c;tds)的质量分数大于3.5&#xff05;的废水&#xff0c;具有水量大&#xff0c;无机盐离子k、na、ca2、mg2、cl-、so42-等含量高&#xff0c;水质水量变化大&#xff0c;成分复杂&#xff0c;难生化降解等特…...

回文日期门牌制作

题目&#xff1a; 题目描述 如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202&#xff0c;恰好是一个回文数。我们称这样的日期是回文日期。20200202 并不仅仅是一个回文日期&#xff0c;还是一个 ABABBABA 型的回文日期。 给定一个 8 位数的日期&#xff0c;请…...

基于半车悬架的轴距预瞄与轴间预瞄仿真对比

目录 前言 1. 半车悬架模型 2.轴距预瞄(单点预瞄)和轴间预瞄(两点预瞄)原理与仿真分析 2.1轴距预瞄(单点预瞄) 2.1.1预瞄原理 2.2.轴间预瞄(两点预瞄) 2.2.1预瞄原理 2.3仿真分析 3.总结 前言 对于悬架而言&#xff0c;四个车轮实际的输入信息是受到前后延时以及左右相…...

Linux开发 安装JDK8、p4

前面的笔记&#xff1a; Linux 学习笔记1 安装linux详细教程_linux系统 setting_O丶ne丨柒夜的博客-CSDN博客 Linux 学习笔记2 常用命令_O丶ne丨柒夜的博客-CSDN博客 Linux 学习笔记3 权限管理 定时任务 网络配置_O丶ne丨柒夜的博客-CSDN博客 安装配置 安装配置JDK8 Java …...

基于 x86 SoC 的车辆智能驾驶舱和ADAS设计(一)

随着汽车成为软件定义的自动化领域的中心&#xff0c;英特尔致力于提供从汽车到云的可扩展安 全解决方案来加快从高级驾驶员辅助系统(ADAS)到全自动汽车为自动驾驶提供技术支持。 2016 年 3 月&#xff0c;英特尔斥资 153 亿美元收购了以色列高级辅助驾驶系统企业 Mobileye。20…...

类模板函数模板

准备看个项目找实习&#xff0c;边看边学&#xff0c;一看到处都是template 和typename&#xff0c;好几年前学的C都忘记光了&#xff0c;在这里先做个笔记复习一下。template <class T> T abs(T x) {if(x < 0) return -x;return x; } int main() {int x 1;cout <…...

Leetcode DAY 56: 两个字符串的删除操作 and 编辑距离

583. 两个字符串的删除操作 1 、 dp[i][j] 表示 让以word1[i - 1]为结尾的字符串 和 以word2[i - 2]为结尾的字符串 相等需要删除的最少次数 1、dp[i][j] 的 递推需要考虑两种情况&#xff1a; &#xff08;1&#xff09;word1[i - 1] word2[j - 1] 相当于不考虑word1[i]和…...

系统检测维护工具Wsycheck使用(18)

实验目的 &#xff08;1&#xff09;学习Wsycheck的基本功能&#xff1b; &#xff08;2&#xff09;掌握Wsycheck的基本使用方法&#xff1b; 预备知识 windows操作系统的基本知识如&#xff1a;进程、网络、服务和文件等的了解。 Wsycheck是一款强大的系统检测维护工具,进程和…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

智能体革命:企业如何构建自主决策的AI代理?

OpenAI智能代理构建实用指南详解 随着大型语言模型&#xff08;LLM&#xff09;在推理、多模态理解和工具调用能力上的进步&#xff0c;智能代理&#xff08;Agents&#xff09;成为自动化领域的新突破。与传统软件仅帮助用户自动化流程不同&#xff0c;智能代理能够自主执行工…...