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;
    }

    @Override
    protected 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的类加载机制,整体流程如下图:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#调用OpenCvSharp实现图像的直方图均衡化

本文学习基于OpenCvSharp的直方图均衡化处理方式&#xff0c;并使用SkiaSharp绘制相关图形。直方图均衡化是一种图像处理方法&#xff0c;针对偏亮或偏暗的图像&#xff0c;通过调整图像的像素值来增强图像对比度&#xff0c;详细原理及介绍见参考文献1-4。   直方图均衡化第…

【中学教资科目二】02中学课程

02中学课程 第一节 课程概述1.1 课程的分类 第二节 课程组织2.1 课程内容的文本表现形式2.2 课程评价 第三节 基础教育课程改革3.1 基础教育改革的目标3.2 新课改的课程结构 第一节 课程概述 1.1 课程的分类 学校课程有多种类型&#xff0c;其中最利于学生系统掌握人类所取得的…

多维表格/业务库表格大数据量性能瓶颈

先说最终结论&#xff1a;Angular 组件创建性能损耗是当下主要的性能瓶颈 理由&#xff1a; 基于以往编辑器性能优化的经验&#xff0c;编辑器在动态渲染内容时会创建很多壳子组件&#xff08;也就是Angular 组件&#xff09;&#xff0c;排查的时候就发现如果略这些壳子组件性…

mysql--安装跳过验证修改密码安全加固

安装mysql 配置mysql的yum源 [rootVM-0-14-rockylinux ~]# tee /etc/yum.repos.d/mysql.repo << EOF > [MYSQL] > namemysql > baseurlhttps://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql-5.7-community-el7-x86_64 > gpgcheck0 > EOF yum安装mysq…

海南聚广众达电子商务咨询有限公司抖音电商新标杆

在数字经济的浪潮中&#xff0c;抖音电商正成为一股不可忽视的力量。海南聚广众达电子商务咨询有限公司&#xff0c;作为专注于抖音电商服务的领军企业&#xff0c;凭借其专业的团队和创新的思维&#xff0c;不断助力商家在抖音平台上实现商业价值的最大化。 海南聚广众达电子…

【ai】tx2-nx:Yolo V4 直接安装与 测试

Yolo V4环境搭建 git clone https://github.com/AlexeyAB/darknet.gitcuda版本和路径也要改成我们的实际版本和路径,否则会编译失败 编译 sudo make nvidia@tx2-nx:~/twork/02_yolov4/darknet$ vi Makefile nvidia@tx2-nx:~/twork/02_yolov4/darknet$ sudo make [sudo

众爱宠物开源项目介绍

众爱宠物管理系统是一个集会员管理、宠物管理、商品管理、库存管理、数据管理、收银管理、多门店管理等功能于一体的综合管理系统&#xff0c;具有操作方便、简单、安全等优点。 开源项目地址

数学建模系列(3/4):典型建模方法

目录 引言 1. 回归分析 1.1 线性回归 基本概念 Matlab实现 1.2 多元回归 基本概念 Matlab实现 1.3 非线性回归 基本概念 Matlab实现 2. 时间序列分析 2.1 时间序列的基本概念 2.2 移动平均 基本概念 Matlab实现 2.3 指数平滑 基本概念 Matlab实现 2.4 ARIM…

Android修行手册-ImageView的adjustViewBounds和设置透明度

点击跳转>GameFramework文档系列&#xff08;二&#xff09;- 场景相关 点击跳转>GameFramework文档系列&#xff08;三&#xff09;- 日志管理和UI 点击跳转>GameFramework文档系列&#xff08;四&#xff09;- 事件订阅 点击跳转>保姆式Cocos合成大西瓜案例 …

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

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

基于强化学习的目标跟踪论文合集

文章目录 2020UAV Maneuvering Target Tracking in Uncertain Environments Based on Deep Reinforcement Learning and Meta-LearningUAV Target Tracking in Urban Environments Using Deep Reinforcement Learning 2021Research on Vehicle Dispatch Problem Based on Kuhn-…

BGP路由反射器实验

实验内容&#xff1a; 通过本实验验证bgp路由反射器的规则 1. 从client收到的路由更新&#xff0c;反射到non-client和client&#xff0c;同时发送给EBGP邻居 2. 从non-client收到的路由更新&#xff0c;只反射到client&#xff0c;同时发送给EBGP邻居 3. 从EBGP邻居收到的路…

PXE自动平台 搭建 银河麒麟 UEFI x86_64 ARM64

1. PXE自动化 原理 要实现PXE自动安装需要以下组件&#xff1a; DHCP服务&#xff1a;服务器通过网络启动时自动分配IP地址。TFTP服务&#xff1a;提供服务器启动下载启动引导EFI。HTTP服务&#xff1a;操作系统镜像下载。 各组件工作原理如下[1]&#xff1a; 开PXE后&…

最新版ChatGPT对话系统源码 Chat Nio系统源码

最新版ChatGPT对话系统源码 Chat Nio系统源码 支持 Vision 模型, 同时支持 直接上传图片 和 输入图片直链或 Base64 图片 功能 (如 GPT-4 Vision Preview, Gemini Pro Vision 等模型) 支持 DALL-E 模型绘图 支持 Midjourney / Niji 模型的 Imagine / Upscale / Variant / Re…

Redis-数据类型-Geospatial(地理空间索引)

文章目录 1、查看redis是否启动2、通过客户端连接redis3、切换到db5数据库4、将地理位置信息&#xff08;经度和纬度&#xff09;添加到 Redis 的键&#xff08;key&#xff09;中4.1、添加大江商厦4.2、添加西部硅谷 5、升序返回有序集key&#xff0c;让分数一起和值返回的结果…

Doris连接超时问题排查记录

文章目录 一、现象描述二、问题排查1、分析驱动包2、分析Mysql客户端&#xff08;问题解决&#xff09; 一、现象描述 先上官网部署地址&#xff0c;按照官网上一步步进行部署 https://doris.apache.org/zh-CN/docs/get-starting/quick-start 基本到最后都挺顺利的&#xff0c…

2022年大作业参考报告-使用C++语言开发小学生成绩管理系统、中学生成绩管理系统、大学生成绩管理系统【240621更新】

背景&#xff1a; 目录 第一章 需求分析 2 1.1 问题描述 2 6.1 功能需求 2 6.2 开发环境 2 6.3 开发过程 2 第二章 概要设计 3 2.1 总体设计 3 2.2 类的定义 3 2.3 接口设计 5 2.4 运行界面设计 6 第三章 详细设计 …

【滚动哈希 二分查找】1044. 最长重复子串

本文涉及知识点 滚动哈希 二分查找算法合集 LeetCode 1044. 最长重复子串 给你一个字符串 s &#xff0c;考虑其所有 重复子串 &#xff1a;即 s 的&#xff08;连续&#xff09;子串&#xff0c;在 s 中出现 2 次或更多次。这些出现之间可能存在重叠。 返回 任意一个 可能具…

vs2022 studio控制台出现中文乱码解决

vs2022 studio控制台出现中文乱码解决 问题解决 问题 这里cout中间的中文&#xff0c;但控制台出现的是乱码对此需要进行修改 解决 打开运行的主文件&#xff0c;也就是整个程序的入口&#xff0c;对他另存为 之后点击编码保存 接着将编码保存的格式变为图片对应的这种 记…

ArcGIS定义1.5度带坐标系与投影转换

​ 点击下方全系列课程学习 点击学习—>ArcGIS全系列实战视频教程——9个单一课程组合系列直播回放 点击学习——>遥感影像综合处理4大遥感软件ArcGISENVIErdaseCognition 对于ArcGIS如何定义高斯克吕格3度带、6度带&#xff0c;我相信大部分人都是比较清楚的&#xff0…