当前位置: 首页 > 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是一款强大的系统检测维护工具,进程和…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成

一个面向 Java 开发者的 Sring-Ai 示例工程项目&#xff0c;该项目是一个 Spring AI 快速入门的样例工程项目&#xff0c;旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计&#xff0c;每个模块都专注于特定的功能领域&#xff0c;便于学习和…...