JVM专题五:类加载器与双亲委派机制

通过上一篇Java的类加载机制相信大家已经搞明白了整个类加载从触发时机,接着我们就来看下类加载器,因为类加载机制是有加载器实现的。 

类加载器的分类

启动类加载器

Bootstrap ClassLoader 是 Java 虚拟机(JVM)的一部分,它负责加载 Java 核心库,也就是 Java Runtime Environment (JRE) 中的类。这些类通常位于 JRE 的 lib 目录下的 rt.jar 文件中,以及可能的其他 JAR 文件,比如 jsse.jar(Java Secure Socket Extension)等。

Bootstrap ClassLoader 是一个虚拟的类加载器,它不继承自 java.lang.ClassLoader,也不可以被直接引用或实例化。它是 JVM 的一部分,并且是所有类加载器的父加载器。当 JVM 启动时,Bootstrap ClassLoader 首先加载 rt.jar 中的类,然后这些类可以被其他类加载器使用。

Bootstrap ClassLoader 的主要作用包括:

  1. 加载 Java 核心库,如 java.lang 包中的类。
  2. 作为类加载器层次结构的根,为其他类加载器提供基础。

扩展类加载器

Extension ClassLoader 是 Java 虚拟机(JVM)中的一个系统类加载器,它负责加载 Java 扩展目录中的类库。以下是关于 Extension ClassLoader 的几个关键点:

  1. 加载职责:Extension ClassLoader 专门用来加载 lib/ext 目录或者由系统属性 java.ext.dirs 指定的其他目录中的类库。这些类库通常包括 Java 平台的标准扩展,例如一些常用的第三方库。

  2. 类加载顺序:在 JVM 的类加载体系中,Extension ClassLoader 位于 Bootstrap ClassLoader 之后。当一个类请求被提交到 JVM 时,Bootstrap ClassLoader 首先尝试加载,如果找不到相应的类,请求会传递给 Extension ClassLoader。

  3. 双亲委派模型:Extension ClassLoader 遵循 Java 的双亲委派模型,这意味着在尝试自己加载类之前,它会先委托给父类加载器(在这个情况下是 Bootstrap ClassLoader)进行加载。

  4. 配置灵活性:开发者可以通过设置 java.ext.dirs 系统属性来指定多个扩展目录,使得 JVM 可以在启动时从这些目录中加载类库。

应用类加载器

Application ClassLoader 是 JVM 中的一个系统类加载器,它的作用是加载应用程序类路径(ClassPath)上指定的类库。以下是 Application ClassLoader 的几个关键点:

1. 加载职责:Application ClassLoader 主要负责加载用户编写的 Java 应用程序代码。这些代码通常位于项目的 `bin` 或 `classes` 目录下,或者是通过 JAR 文件提供的。

2. 类加载顺序:在 JVM 的类加载器层级中,Application ClassLoader 位于 Extension ClassLoader 之后。这意味着,如果一个类同时在扩展目录和应用程序类路径中存在,Extension ClassLoader 会优先加载它。

3. 双亲委派模型:和 Extension ClassLoader 一样,Application ClassLoader 也遵循双亲委派模型。当它需要加载一个类时,会先委托给父类加载器(Extension ClassLoader)尝试加载,如果父类加载器无法加载,Application ClassLoader 才会尝试从应用程序类路径加载。

4. 灵活性:开发者可以通过设置系统属性 `java.class.path` 或使用 `-cp` 或 `-classpath` 命令行选项来指定应用程序类路径,从而控制 Application ClassLoader 加载的类库。

简而言之,Application ClassLoader 是我们程序员在 Java 应用程序开发过程中接触最多的类加载器,它负责将编写的 Java 类加载到 JVM 中,是 Java 应用程序运行的基础。其实你大致就理解为去加载你写好的Java代码,这个类加载器就负责加载你写好的那些类到内存里

自定义类加载器

自定义类加载器是 Java 动态加载类的一种强大机制,它允许开发者根据特定的需求来加载类。这种机制特别有用在需要动态加载或更新类定义的场景中,例如在热部署、模块化应用、或者需要从非标准源加载类文件等情况下。以下是 自定义类加载器的几个关键点:

  1. 继承性:自定义类加载器需要继承 java.lang.ClassLoader 类,并重写 findClass 方法来实现自定义的类查找逻辑。

  2. 加载逻辑:开发者可以在 findClass 方法中实现自己的类加载逻辑,例如从数据库、网络、文件系统等非标准位置加载类文件。

  3. 双亲委派模型:自定义类加载器同样遵循 Java 的双亲委派模型。在尝试加载类之前,它会委托给父类加载器,如果父类加载器无法加载,自定义类加载器才会介入。

  4. 隔离性:自定义类加载器可以创建与系统类加载器和应用程序类加载器隔离的类,这有助于实现模块化和防止类冲突。

  5. 安全性:自定义类加载器可以提供额外的安全检查,例如验证类文件的来源或内容,确保加载的类是安全的。

  6. 灵活性:通过自定义类加载器,开发者可以控制类的加载时机、来源和方式,为 Java 应用程序提供更高的灵活性和可扩展性。

  7. 使用场景:自定义类加载器适用于需要动态加载类、实现类版本控制、或者需要加载特定格式类文件的应用程序。

        通过自定义类加载器,Java 应用程序可以突破传统的类加载限制,实现更加灵活和动态的类加载策略。这对于需要高度定制化和模块化的应用程序尤其重要。下面提供简单的代码实例:

import java.io.*;
import java.nio.file.*;
import java.util.logging.*;public class MyClassLoader extends ClassLoader {private static final Logger LOGGER = Logger.getLogger(MyClassLoader.class.getName());private final String classPath;private final boolean verify;public MyClassLoader(String classPath) {this(classPath, true);}public MyClassLoader(String classPath, boolean verify) {this.classPath = classPath;this.verify = verify;}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {String fileName = name.replace('.', '/') + ".class";byte[] classData = loadClassData(fileName);if (classData == null) {throw new ClassNotFoundException("Could not find " + fileName + " in " + classPath);}if (verify) {verifyClassData(classData);}return defineClass(name, classData, 0, classData.length);}private byte[] loadClassData(String fileName) throws IOException {Path path = Paths.get(classPath, fileName);try (InputStream in = Files.newInputStream(path)) {return in.readAllBytes();}}private void verifyClassData(byte[] classData) {// 这里可以添加对类数据的验证逻辑LOGGER.info("Class data verification is not implemented yet.");}public static void main(String[] args) {try {String classPath = "path/to/your/classes"; // 替换为实际的类文件路径MyClassLoader myClassLoader = new MyClassLoader(classPath);Class<?> myClass = myClassLoader.loadClass("com.example.MyClass");Object instance = myClass.getDeclaredConstructor().newInstance();// 假设 MyClass 有一个 sayHello 方法java.lang.reflect.Method sayHelloMethod = myClass.getMethod("sayHello");sayHelloMethod.invoke(instance);} catch (Exception e) {LOGGER.log(Level.SEVERE, "Error loading class", e);}}
}

双亲委派机制

双亲委派机制层级结构

JVM的类加载器是有亲子层级结构的,就是说启动类加载器是最上层的,扩展类加载器在第二层,第三层是应用程序类加载器,最后一层是自定义类加载器,虽然说是最后一层,但是因为我们可以无限自定义,所以其实就是树的结构,深度可以不断累加。如下图:

为什么需要双亲委派机制?

双亲委派机制是 Java 类加载机制的核心原则之一,其设计具有以下几个重要目的:

  1. 安全性:双亲委派机制确保了 Java 核心库的类不能被随意替换或篡改。因为只有引导类加载器(Bootstrap ClassLoader)才能加载 rt.jar 中的 Java 核心类库,而它是不可扩展的。这防止了恶意代码对 Java 核心库的破坏。

  2. 避免类的重复加载:通过委托给父类加载器,JVM 确保了一个类在 JVM 内只被加载一次。这避免了类的重复加载,节省了内存资源,并且保证了类的唯一性。

  3. 保证加载顺序:双亲委派模型保证了类按照既定的顺序加载,例如,Java 核心库总是首先加载,然后是扩展库,最后是应用程序类。这有助于维护程序的稳定性和可预测性。

  4. 封装性和层次性:双亲委派模型允许 Java 应用程序分层,每一层都有自己的类加载器。这有助于实现模块化,使得不同层次的代码可以独立地更新和替换,而不会影响到其他层次。

  5. 类空间隔离:在复杂的应用程序中,如 Web 容器或 OSGi 框架,双亲委派模型通过使用不同的类加载器来实现类空间的隔离。这使得不同的模块或应用可以加载相同类的不同版本,而不会相互冲突。

  6. 易于实现和维护:双亲委派模型的实现相对简单,逻辑清晰,易于理解和维护。开发者可以专注于实现自己的 findClass 方法,而不必担心类加载的委托逻辑。

  7. 灵活性:虽然双亲委派模型是 Java 类加载的默认策略,但它并不是强制性的。开发者可以通过自定义类加载器来实现特定的类加载逻辑,例如,从数据库或网络加载类。

  8. 优化性能:通过缓存已加载的类(在 ClassLoader 中的 classes 集合中),JVM 可以快速检查类是否已经被加载,从而避免不必要的加载过程,提高性能。

简而言之,双亲委派机制为 Java 类加载提供了一种安全、有效、可预测的策略,有助于维护 Java 应用程序的稳定性和性能。

Tomcat真的破双亲委派机制了嘛?

Tomcat 并没有打破 Java 的双亲委派模型,而是在双亲委派模型的基础上进行了适应 Web 容器需求的扩展。下面是几个关键点来说明这一点:

  1. 双亲委派模型的核心:双亲委派模型的核心是,当一个类加载器收到类加载请求时,它会先委托给父类加载器去尝试加载这个类,直到达到启动类加载器。如果父类加载器无法完成加载任务,才会由子类加载器尝试加载。

  2. Tomcat 类加载器的实现:Tomcat 实现了多个层次的类加载器,包括 Common ClassLoader、Server ClassLoader、Shared ClassLoader 和 Webapp ClassLoader。这些类加载器都遵循双亲委派模型的委派逻辑。

  3. Webapp ClassLoader 的特殊性:虽然 Tomcat 的 Webapp ClassLoader 允许 Web 应用加载自己版本的类,但这是通过实现自己的 findClass 方法来实现的,而不是通过重写 loadClass 方法来绕过双亲委派模型。Webapp ClassLoader 仍然会首先委托父类加载器尝试加载类。

  4. 线程上下文类加载器(TCCL):Tomcat 在执行请求时,会将当前 Web 应用的类加载器设置为 TCCL。这确保了请求处理过程中加载的类首先会使用 Webapp ClassLoader,但这个过程仍然是在双亲委派模型的框架内进行的。

  5. 隔离性和灵活性:Tomcat 的类加载器设计提供了类隔离和版本控制的灵活性,这并不违反双亲委派模型,而是扩展了类加载器的使用场景。

类加载器实际的关系

        双亲委派机制,最早我一直以为是子类继承父类,其实看到源码以后发现实际上并没有继承关系,而是有成员变量取名叫parent,所以‘亲’由此而来;他们之间是组合关系并非是继承嗷!

        说到这里,本来该结束了,突然想到Effective Java中有一条原则是:组合优于继承?有小伙伴知道吗?哈哈这里就不展开了,后续会在设计模式模块好好唠唠。

结合上述类加载器,回头看看类加载机制忘了的小伙伴可以看上篇文章Java的类加载机制,整体流程如下图:

现在我们已经了解到了如何把文件加载到JVM里了,那从JVM角度考虑这些类的数据应该存放到什么位置呢?运行时候产生的动态数据又该放到哪里呢?

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

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

相关文章

数据挖掘概览

数据挖掘(Data Mining)就是从大量的,不完全的,有噪声的,模糊的,随机的实际应用数据中,提取隐含在其中的,人们事先不知道的,但又是潜在有用的信息和知识的过程. 预测性数据挖掘 分类 定义&#xff1a;分类就是把一些新的数据项映射到给定类别中的某一个类别 分类流程&#x…

AI办公自动化:免费批量将英语电子书转成有声书

Edge-TTS是由微软推出的文本转语音Python库&#xff0c;通过微软Azure Cognitive Services转化文本为自然语音。可以作为付费文本转语音TTS服务的替代品&#xff0c;Edge-TTS支持40多种语言和300种声音&#xff0c;提供优质的语音输出 。 edge-tts支持英语、汉语、日语、韩语、…

小阿轩yx-MySQL数据库管理

小阿轩yx-MySQL数据库管理 使用 MySQL 数据库 在服务器运维工作中不可或缺的 SQL &#xff08;结构化查询语句&#xff09;的四种类型 数据定义语言&#xff08;DDL&#xff09;&#xff1a;DROP&#xff08;删除&#xff09;、CREATE&#xff08;创建&#xff09;、ALTER&…

基于rouyi框架的多租户改造

基于rouyi框架的多租户改造&#xff0c;重点是实现权限管理和数据隔离。权限管理相当于从原来的“顶级管理员admin-普通用户user”转变为“顶级管理员admin-租户管理员tanantAdmin-普通用户user”。数据隔离主要通过分库、分表、表内设置tenantId字段进行过滤三种方式。 本文主…

由于bug造成truncate table卡住问题

客户反应truncate table卡主&#xff0c;检查awr发现多个truncate在awr报告期内一直没执行完&#xff0c;如下&#xff1a; 检查ash&#xff0c;truncate table表的等待事件都是“enq: RO - fast object reuse”和“local write wait” 查找“enq: RO - fast object reuse”&am…

爬虫笔记15——爬取网页数据并使用redis数据库set类型去重存入,以爬取芒果踢V为例

下载redis数据库 首先需要下载redis数据库&#xff0c;可以直接去Redis官网下载。或者可以看这里下载过程。 pycharm项目文件下载redis库 > pip install redis 然后在程序中连接redis服务&#xff1a; from redis import RedisredisObj Redis(host127.0.0.1, port6379)…

Django模板

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 Django指定的模板引擎在settings.py文件中定义&#xff0c;代码如下&#xff1a; TEMPLATES [{ # 模板引擎&#xff0c;默认为Django模板 BACKEND:…

SpringMVC框架中常用的几种切面Fliter、Aspect、Interceptor、Advice功能对比和应用场景

1.过滤器&#xff1a;Filter接口 参数校验&#xff1a;用户输入的参数可能包含恶意字符或参数格式错误&#xff0c;通过使用Filter可以拦截并进行参数校验&#xff0c;以保证应用安全。 多语言选择&#xff1a;通过获取请求头的语言参数&#xff0c;Filter可以根据用户的语言…

MySQL连接

MySQL工具包 MySQL实现简单链接 一 引入工具包 JBDCUtils&#xff0c;无需更改&#xff0c;直接使用即可。 import java.io.IOException; import java.io.InputStream; import java.sql.*; import java.util.Properties;public class JDBCUtil {private static String URL;p…

国标GB28181视频汇聚平台EasyCVR设备展示数量和显示条数不符的原因排查与解决

国标GB28181/GA/T1400协议/安防综合管理系统EasyCVR视频汇聚平台能在复杂的网络环境中&#xff0c;将前端设备统一集中接入与汇聚管理。智慧安防/视频存储/视频监控/视频汇聚EasyCVR平台可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级…

Kotlin设计模式:深入解析Facade模式

Kotlin设计模式&#xff1a;深入解析Facade模式 在软件开发中&#xff0c;随着系统复杂度的增加&#xff0c;管理和使用多个相关接口变得越来越困难。这时候&#xff0c;Facade模式&#xff08;外观模式&#xff09;就显得尤为重要。本文将深入探讨Kotlin中的Facade模式&#…

Linux CentoS安装RabbitMQ:一键安装指南

有两种安装方法&#xff0c;官方推荐使用 docker安装RabbitMQ 一、Docker安装RabbitMQ 1、安装docker 参考我之前的文章&#xff1a;Centos7.5搭建docker并且部署Lnmp环境&#xff08;小白入门docoker&#xff09;_centos7.5安装docker和docker-compose-CSDN博客 2、安装Ra…

美食解压视频素材无水印无字幕的在哪找?海外美食解压网站分享

在如今快节奏的生活中&#xff0c;观看美食视频已成为许多人缓解压力的一种方式。这些视频不仅唤醒人们的味觉记忆&#xff0c;还能在繁忙中带来片刻的放松。然而&#xff0c;对于视频创作者来说&#xff0c;寻找高品质的美食视频素材&#xff0c;特别是那些无水印、无字幕、可…

利用SHAP算法解释BERT模型的输出

1 何为SHAP? 传统的 feature importance 只告诉哪个特征重要&#xff0c;但并不清楚该特征如何影响预测结果。SHAP 算法的最大优势是能反应每一个样本中特征的影响力&#xff0c;且可表现出影响的正负性。SHAP算法的主要思想为&#xff1a;控制变量法&#xff0c;如果某个特征…

养殖自动化温控系统:现代养殖场的智能守护神

现代农业养殖业中&#xff0c;养殖自动化温控系统已经成为提高生产效率和保障动物福利的关键技术之一。本篇文章将深入介绍养殖自动化温控系统的原理、组成、优势及其在不同类型养殖场中的应用实例&#xff0c;并展望该技术的未来发展。 一、养殖自动化温控系统概述 养殖自动…

数据结构——优先级队列(堆)Priority Queue详解

1. 优先级队列 队列是一种先进先出(FIFO)的数据结构&#xff0c;但有些情况下&#xff0c;操作的数据可能带有优先级&#xff0c;一般出队列时&#xff0c;可能需要优先级高的元素先出队列&#xff0c;该场景下&#xff0c;使用队列不合适 在这种情况下&#xff0c;数据结构应…

[笔记] CCD相机测距相关的一些基础知识

1.35mm胶片相机等效焦距 https://zhuanlan.zhihu.com/p/419616729 拿到摄像头拍摄的数码照片后&#xff0c;我们会看到这样的信息&#xff1a; 这里显示出了两个焦距&#xff1a;一个是实际焦距&#xff1a;5mm&#xff0c;一个是等效焦距&#xff1a;25mm。 实际焦距很容易…

HarmonyOS Next 系列之可移动悬浮按钮实现(六)

系列文章目录 HarmonyOS Next 系列之省市区弹窗选择器实现&#xff08;一&#xff09; HarmonyOS Next 系列之验证码输入组件实现&#xff08;二&#xff09; HarmonyOS Next 系列之底部标签栏TabBar实现&#xff08;三&#xff09; HarmonyOS Next 系列之HTTP请求封装和Token…

Pytorch Geometric(PyG)入门

PyG (PyTorch Geometric) 是建立在 PyTorch 基础上的一个库&#xff0c;用于轻松编写和训练图形神经网络 (GNN)&#xff0c;适用于与结构化数据相关的各种应用。官方文档 Install PyG PyG适用于python3.8-3.12 一般使用场景&#xff1a;pip install torch_geometric 或conda …

百度地图3d区域掩膜,最常见通用的大屏地图展现形式

需求及效果 原本项目使用的是百度地图3.0,也就是2d版本的那个地图,客户不满意觉得不够好看,让把地图改成3d的,但是我们因为另外的系统用的都是百度地图,为了保持统一只能用百度地图做 经过3天的努力,最后我终于把这个效果实现了,效果如下: 如何引用GL版本 为了实现…