当前位置: 首页 > 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执行。类…...

高斯分布、高斯混合模型、EM算法详细介绍及其原理详解

相关文章 K近邻算法和KD树详细介绍及其原理详解朴素贝叶斯算法和拉普拉斯平滑详细介绍及其原理详解决策树算法和CART决策树算法详细介绍及其原理详解线性回归算法和逻辑斯谛回归算法详细介绍及其原理详解硬间隔支持向量机算法、软间隔支持向量机算法、非线性支持向量机算法详细…...

[Linux入门篇]一篇博客解决C/C++/Linux System Call文件操作接口的使用

目录 0.前言 1.C / C ->文件操作 1.1 C语言文件操作 1.1.1 C语言文件打开/关闭/写入 1.1.2 C语言文件的追加操作 1.1.3 C语言文件的读取 1.2 C语言文件操作 1.2.1 C文件打开 / 关闭 / 写入 1.2.2 C文件读取 1.2.3 文件追加 2.三个默认输入输出流 2.1 C语言中的三…...

数据结构和算法学习记录——删除有序数组中的重复项、合并两个有序数组

去重删除有序数组中的重复项题目来自&#xff1a;https://leetcode.cn/problems/remove-duplicates-from-sorted-array/description/题目描述给你一个 升序排列 的数组 nums &#xff0c;请你原地删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数…...

FPGA实现模拟视频BT656解码 TW2867四路PAL采集拼接显示 提供工程源码和技术支持

目录1、前言2、模拟视频概述3、模拟视频颜色空间4、逐行与隔行5、BT656数据与解码BT656数据格式BT656数据解码6、TW2867芯片解读与配置TW2867芯片解读TW2867芯片配置TW2867时序分析7、设计思路与框架8、vivado工程详解9、上板调试验证10、福利&#xff1a;工程代码的获取1、前言…...

【建议收藏】超详细的Canal入门,看这篇就够了!!!

概述 canal是阿里巴巴旗下的一款开源项目&#xff0c;纯Java开发。基于数据库增量日志解析&#xff0c;提供增量数据订阅&消费&#xff0c;目前主要支持了MySQL&#xff08;也支持mariaDB&#xff09;。 背景 早期&#xff0c;阿里巴巴B2B公司因为存在杭州和美国双机房部…...

KubeSphere 社区双周报 | OpenFunction v1.0.0-rc.0 发布

KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过 commit 的贡献者&#xff0c;并对近期重要的 PR 进行解析&#xff0c;同时还包含了线上/线下活动和布道推广等一系列社区动态。 本次双周报涵盖时间为&#xff1a;2023.02.17-2023.…...

查漏补缺3月

SPI扩展序列化方式 分布式ID的相关问题 TCP的流量控制&#xff0c;避免浪费网络资源的滑动平均法也可以用在其他可能会出现资源浪费的情况等 讲一讲对自己这个 RPC 项目的想法&#xff0c;你是怎么设计这个项目的&#xff0c;想要实现那些功能&#xff1f; 你认为一个好的 RPC…...

如何使用Java实现类似Windows域登录

什么是域登录&#xff1f; 域登录是一种集中式身份验证和授权方法&#xff0c;用于访问企业内部网络和资源。在Windows环境中&#xff0c;域是一组计算机和用户帐户的集合&#xff0c;受到单个安全管理的控制。域登录允许用户在访问域资源时使用单个帐户名和密码进行身份验证&…...

生成模型与判别模型

生成模型与判别模型 一、决策函数Yf(X)或者条件概率分布P(Y|X) 监督学习的任务就是从数据中学习一个模型&#xff08;也叫分类器&#xff09;&#xff0c;应用这一模型&#xff0c;对给定的输入X预测相应的输出Y。这个模型的一般形式为决策函数Yf(X)或者条件概率分布P(Y|X)。 …...

Kotlin lateinit 和 lazy 之间的区别 (翻译)

Kotlin 中的属性是使用var或val关键字声明的。Late init 和 lazy 都是用来初始化以后要用到的属性。 由于这两个关键字都用于声明稍后将要使用的属性&#xff0c;因此让我们看一下它们以及它们的区别。 Late Init 在下面的示例中&#xff0c;我们有一个变量 myClass&#xff0…...

Golang alpine Dockerfile 最小打包

最近在ubantu 上进行了 iris项目的alpine 版本打包&#xff0c;过程遇到了一些问题&#xff0c;记录一下。 golang版本 &#xff1a;1.18 系统&#xff1a;ubantu 代码结构 Dockfile内容 FROM alpine:latest MAINTAINER Si Wei<3320376695qq.com> ENV VERSION 1.1 ENV G…...

在NVIDIA JetBot Nano小车上更新WIFI驱动

前言:树莓派上的WIFI驱动类型比较多&#xff0c;经常有更好驱动的需求本文给出RealTek的无线WIFI模组&#xff0c;8821CU的驱动更新办法步骤第一 通过其他方式连接网络小车通过网线或者老的WIFI连接到网络上第二 构建驱动模块并下载驱动首先&#xff0c;我们需要打开一个ubuntu…...

2023年网络安全最应该看的书籍,弯道超车,拒绝看烂书

学习的方法有很多种&#xff0c;看书就是一种不错的方法&#xff0c;但为什么总有人说&#xff1a;“看书是学不会技术的”。 其实就是书籍没选对&#xff0c;看的书不好&#xff0c;你学不下去是很正常的。 一本好书其实不亚于一套好的视频教程&#xff0c;尤其是经典的好书…...

VSYNC研究

Vsync信号是SurfaceFlinger进程中核心的一块逻辑&#xff0c;我们主要从以下几个方面着手讲解。软件Vsync是怎么实现的&#xff0c;它是如何保持有效性的&#xff1f;systrace中看到的VSYNC信号如何解读&#xff0c;这些脉冲信号是在哪里打印的&#xff1f;为什么VSYNC-sf / VS…...

python gRPC:根据.protobuf文件生成py代码、grpc转换为http协议对外提供服务

文章目录python GRPC&#xff1a;根据.protobuf文件生成py代码grpcio-tools安装和使用python GRPC的官网示例grpc转换为http协议对外提供服务工作问题总结grpc-ecosystem/grpc-gateway/third_party/googleapis: warning: directory does not exist.python GRPC&#xff1a;根据…...

Allegro如何输出ODB文件操作指导

Allegro如何输出ODB文件操作指导 在PCB设计完成之后,需要输出生产文件用于生产加工,除了gerber文件可以用生产制造,ODB文件同样也可以用于生产,如下图 用Allegro如何输出ODB文件,具体操作如下 首先确保电脑上已经安装了ODB这个插件,版本不受限制点击File...

koa-vue的分页实现

1.引言 最近确实体会到了前端找工作的难处&#xff0c;不过大家还是要稳住心态&#xff0c;毕竟有一些前端大神说的有道理&#xff0c;前端发展了近20年&#xff0c;诞生了很多leader级别的大神&#xff0c;这些大神可能都没有合适的坑位&#xff0c;我们新手入坑自然难一些&am…...

安全开发基础 -- DAST,SAST,IAST简单介绍

安全开发基础-- DAST&#xff0c;SAST&#xff0c;IAST 简介 DAST 动态应用程序安全测试&#xff08;Dynamic Application Security Testing&#xff09;技术在测试或运行阶段分析应用程序的动态运行状态。它模拟黑客行为对应用程序进行动态攻击&#xff0c;分析应用程序的反…...

网络安全之暴力破解介绍及暴力破解Tomcat

网络安全之暴力破解介绍及应用场景一、暴力破解介绍1.1 暴力破解介绍1.2 暴力破解应用场景一、暴力破解Tomcat一、暴力破解介绍 1.1 暴力破解介绍 暴力破解字典&#xff1a;https://github.com/k8gege/PasswordDic 1.2 暴力破解应用场景 一、暴力破解Tomcat 登录Tomcat后台&a…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...

tomcat指定使用的jdk版本

说明 有时候需要对tomcat配置指定的jdk版本号&#xff0c;此时&#xff0c;我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

vue3 daterange正则踩坑

<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...

Spring AOP代理对象生成原理

代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】&#xff0c;这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...