双亲委派机制与类加载器的自定义

news2024/9/27 19:16:09

类加载器的作用与位置

  

在java字节码文件交给JVM运行时,需要类加载器子系统进行加载,类加载器子系统主要分为

三个阶段加载 链接 初始化具体可以看我前两篇博客这里就不再赘述

加载阶段主要有三个加载器引导类加载器 扩展类加载器 系统类加载器完成

他们的作用就是加载class文件到内存中,具体来说是把数据结构等信息存放在方法区,生成Class模板存放在堆区

三个加载器的关系

引导类加载器由c/c++代码编写,扩展类加载器和系统类加载器由java编写都继承于ClassLoader,他们三者属于层级关系,并不是继承

  ClassLoader classLoader = son.class.getClassLoader();
  System.out.println(classLoader);
  System.out.println(classLoader.getParent());

Parent只是类的属性用于实现双亲委派并非是使用extends的继承关系

这里为类的加载器的parent字段赋值

扩展类和系统类加载器的加载

   

在 Java 虚拟机中,扩展类加载器和系统类加载器都是由启动类加载器加载的。

启动类加载器(Bootstrap Class Loader)是 Java 虚拟机的一部分,负责加载 Java 的核心类库,如 java.lang.Object 和 java.lang.String 等。启动类加载器通常是由 Java 虚拟机的实现提供,它是用本地代码实现的,不是一个普通的 Java 类。

扩展类加载器(Extension Class Loader)和系统类加载器(System Class Loader)都是普通的 Java 类,它们实际上是由启动类加载器加载的。启动类加载器在启动 Java 虚拟机时就已经存在,它会负责加载扩展类加载器和系统类加载器。这样就形成了一个层次结构,启动类加载器位于最顶层,扩展类加载器和系统类加载器位于其下。

扩展类加载器初始化过程

扩展类加载器的初始化参数ClassLoader为null这也就是为什么通过扩展类加载器获得(父类)加载器结果为null

系统类加载器初始化过程

可以看到var1就是上一步创建的扩展类加载器,这也是为什么系统类加载器的(父类)是扩展类加载器

类的加载过程

一个类加载器只会加载一次类,每个加载器会存放加载过的类的全类名,这样保证每个类只加载一次,以自定义类为例子,当使用new 关键字时,先由系统类加载器向上访问扩展类加载器,然后由扩展类加载器向上查看系统类加载器能否加载,当系统类加载器发现不能加载后就由扩展类加载器尝试加载,由于是自定义类,扩展类加载器也不能加载,接着再由系统类加载器加载。每次加载类时都是先判断上级加载器是否可以加载,如果不能再一次向下直到找到合适的类加载器。

这就是双亲委派

ClassLoader的loadClass方法

这就是上述双亲委派的实现机制

如果resolve为true就会进行解析,把符号引用转为直接引用

双亲委派机制

优势:

避免了类的重复加载

保护了java的核心API避免被篡改

劣势

  1. 灵活性受限:双亲委派机制对于自定义类加载器的灵活性有一定的限制。由于双亲委派机制会优先委派给父类加载器加载类,自定义类加载器无法覆盖或修改父类加载器加载的类。这在某些特定的场景下可能会限制了类加载的灵活性和自定义性。

  2. 安全性问题:尽管双亲委派机制可以提供一定的安全性,防止恶意类的加载,但在某些情况下也可能引发安全性问题。如果恶意代码能够伪装成一个被父类加载器加载的类,它可能会绕过子类加载器的安全检查,从而在应用程序中执行恶意操作。

  3. 类加载器冲突:在某些情况下,双亲委派机制可能会导致类加载器冲突。当多个类加载器同时加载同一个类时,由于双亲委派机制的存在,可能会导致类的多次加载或类加载器之间的冲突。这可能会引发类的不兼容性或其他运行时问题。

  4. 动态更新的困难:双亲委派机制在类加载时会优先从父类加载器中寻找已加载的类,这可能会导致动态更新的困难。即使应用程序中存在新版本的类文件,由于父类加载器已加载了旧版本的类,新版本的类可能无法被加载和使用,除非重新启动应用程序或使用特殊的技术来实现动态更新。

  5. 检查类是否加载的过程是单向的

双亲委派的破坏

第一次:

由于jdk1.2之前没有实现双亲委派机制,在1.2时引入双亲委派代码的实现但是ClassLoader是一个抽象类,如果实现的时候重写loadClass方法就会导致双亲委派的失效,所以又定义了一个finClass方法,在保持双亲委派的同时用户还能自己定义findClass方法

第二次

  主要为了解决双亲委派模型的缺陷--类的单项加载,引入了线程上下文类加载器;

这个加载器可以通过Thread类的setContextClassLoader方法进行设置,如果创建线程时未设置就继承自父线程,如果都没设置就默认是应用程序类加载器

 第三次

   主要为了解决java代码无法代码热替换,模块部署,动态更新问题。由IBM主导的OSGI实现模块化热部署的关键就是类的加载器的实现每个模块都有自己的加载器,当更新时连同模块和类的加载器一起换掉就实现了代码的热部署

类加载器的重写

一:如果要改变双亲委派就重写loadClass方法

二:使用双亲委派就重写findClass方法

public class MyClassLoad extends ClassLoader{
    String byteCode;
    public MyClassLoad(ClassLoader parent , String byteCode){
        super(parent);
        this.byteCode = byteCode;
    }
    public MyClassLoad(String byteCode){
        this.byteCode = byteCode;
    }
    @Override
    protected Class findClass(String name) throws ClassNotFoundException {
        String url = byteCode+name+".class";
        Class aClass = null;
        BufferedInputStream ios = null;
        ByteArrayOutputStream ots = null;
        try {
             ios = new BufferedInputStream(new FileInputStream(url));
            byte[] bytes = new byte[1024];
            int led = 0;
             ots = new ByteArrayOutputStream();

            while ((led =ios.read(bytes)) != -1) {
                ots.write(bytes, 0, led);
            }
            byte[] bytes1 = ots.toByteArray();

            aClass = defineClass(null,bytes1, 0, bytes1.length);

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(ios!=null) {
                try {
                    ios.close();
                    ots.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return aClass;
    }


}

接下来解决代码热部署

主方法不停的加载类并创建r的实例对象,要先编译r.java的文件

public class r {

    public r(){
        System.out.println("开始");
    }
}

此时控制台结果

此时修改r的构造方法输出“开始zhong”

此时在使用前端编译器javac编译r.java文件( javac -encoding UTF-8 r.java解决编码问题)

这样就实现了代码的热部署

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pytorch中.to(device) 和.cuda()的区别

在PyTorch中,使用GPU加速可以显著提高模型的训练速度。在将数据传递给GPU之前,需要将其转换为GPU可用的格式。 函数原型如下: def cuda(self: T, device: Optional[Union[int, device]] None) -> T:return self._apply(lambda t: t.cuda…

六、Big Data Tools安装

1、安装 在Jetbrains的任意一款产品中,均可安装Big Data Tools这个插件。 2、示例 下面以DadaGrip为例: (1)打开插件中心 (2)搜索Big Data Tools,下载 3、链接hdfs (1&#xff0…

Java 代码 格式化插件

Java代码 格式化插件 文章目录 Java代码 格式化插件一. 前言1.1 官网1.2 概念1.3 格式化更变规则 二. 使用2.1 插件添加2.2 使用 一. 前言 1.1 官网 spring-javaformat-maven-plugin 1.2 概念 一组可应用于任何 Java 项目以提供一致的“Spring”风格的插件。该套件目前包括…

解决vue element - ui 弹窗打开表单自动校验问题

1 打开弹窗清除自动校验 在data 里面把所有表单字段都定义一下 2 弹窗关闭事件 清除校验

xss-labs靶场1-5关

文章目录 前言一、靶场需要知道的前置知识点1、什么是xss攻击?2、xss攻击分为几大类1、反射型xss2、存储型xss3、dom型xss 3、xss攻击形成的条件 二、xss-labs关卡1-51、关卡12、关卡23、关卡34、关卡45、关卡5 总结 前言 此文章只用于学习和反思巩固xss攻击知识&a…

C语言scanf_s函数的使用

因为scanf函数存在缓冲区溢出的可能性;提供了scanf_s函数;增加一个参数; scanf_s最后一个参数是缓冲区的大小,表示最多读取n-1个字符; 下图代码; 读取整型数可以不指定长度;读取char&#xf…

Vue typescript项目配置eslint+prettier

1.安装依赖 安装 eslint yarn add eslint --dev安装 eslint-plugin-vue yarn add eslint-plugin-vue --dev主要用于检查 Vue 文件语法 安装 prettier 及相关插件 yarn add prettier eslint-config-prettier eslint-plugin-prettier --dev安装 typescript 解析器、规则补充 …

Ubuntu下载离线安装包

旧版Ubuntu下载地址 https://old-releases.ubuntu.com/releases/ 下载离线包 sudo apt-get --download-only -odir::cache/ncayu install net-tools下载snmp离线安装包 sudo apt-get --download-only -odir::cache/root/snmp install snmp snmpd snmp-mibs-downloadersudo a…

2023 年爆肝将近 20 万字讲解最新 JavaEE 全栈工程师基础教程(更新中)

1. Java 语言基本概述 Java 是一种广泛使用的编程语言,由 James Gosling 在 Sun Microsystems(现在是 Oracle Corporation 的一部分)于 1995 年发表。Java 是一种静态类型的、类基础的、并发性的、面向对象的编程语言。Java 广泛应用于企业级…

【Java】异常处理及其语法、抛出异常、自定义异常(完结)

🌺个人主页:Dawn黎明开始 🎀系列专栏:Java ⭐每日一句:道阻且长,行则将至 📢欢迎大家:关注🔍点赞👍评论📝收藏⭐️ 文章目录 一.🔐异…

idea Maven Helper插件使用方法

idea Maven Helper插件使用方法 文章目录 idea Maven Helper插件使用方法📆1.安装mavenhelper🖥️2.使用教程📌3.解决冲突📇4.列表展示依赖🧣5.tree展示依赖🖥️6.搜索依赖🖊️7.最后总结 &…

css鼠标横向滚动并且不展示滚动条几种方法

需求&#xff1a;实现内容超出之后使用属性滚轮进行左右查看超出内容&#xff0c;并且隐藏滚动条 1.不使用框架实现 每次滚动就滚动40px的距离 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name&quo…

【学习记录】从0开始的Linux学习之旅——编译linux内核

一、学习背景 从接触嵌入式至今&#xff0c;除了安装过双系统接触了一丢丢linux外&#xff0c;linux在我眼中向来是个传说。而如今得到了一块树莓派&#xff0c;于是决心把linux搞起来。 二、概念学习 Linux操作系统通常是基于Linux内核&#xff0c;并结合GNU项目中的工具和应…

gitBash中如何使用Linux中的tree命令

文章目录 在gitBash中安装tree的目的如何安装安装完成,就可以直接完美适配Linux系统了在gitBash中安装tree的目的 如下图,powershell虽然可以看做是window下的Linux系统,但是根本就不适配很多Linux中的命令 如何安装 tree.exe安装网址 下载 tree 命令的 二进制包,安装 tr…

Python数据分析实战-爬取以某个关键词搜索的最新的500条新闻的标题和链接(附源码和实现效果)

实现功能 通过百度引擎&#xff0c;爬取以“开源之夏”为搜索关键词最新的500条新闻的标题和链接 实现代码 1.安装所需的库&#xff1a;你需要安装requests和beautifulsoup4库。可以使用以下命令通过pip安装&#xff1a; pip install requests beautifulsoup42.发起搜索请求…

PyCharm玩转ESP32

想必玩ESP32的童鞋都知道Thonny&#xff0c;当然学Python的童鞋用的更多的可能是PyCharm和VsCode Thonny和PyCharm的对比 对于PyCharm和VsCode今天不做比较&#xff0c;今天重点说一下用PyCharm玩转ESP32&#xff0c;在这之前我们先对比下Thonny和PyCharm的优缺点 1、使用Tho…

微信小程序 prettier 格式化

一、安装prettier插件 二、打开设置 然后再打开setting.json 新增代码 {"editor.formatOnSave": true,"editor.defaultFormatter": "esbenp.prettier-vscode","prettier.documentSelectors": ["**/*.wxml", "**/*.wx…

竞赛选题 身份证识别系统 - 图像识别 深度学习

文章目录 0 前言1 实现方法1.1 原理1.1.1 字符定位1.1.2 字符识别1.1.3 深度学习算法介绍1.1.4 模型选择 2 算法流程3 部分关键代码 4 效果展示5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 毕业设计 图像识别 深度学习 身份证识别…

竞赛选题 车位识别车道线检测 - python opencv

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习 机器视觉 车位识别车道线检测 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) …

数据中台之用户画像

用户画像应用领域较为广泛,适合于各个产品周期,从新用户的引流到潜在用户的挖掘、 从老用户 的培养到流失用户的回流等。通过挖掘用户兴趣、偏好、人口统计特征,可以 直接 作用于提升营销精准 度、推荐匹配度,最终提升产品服务和企业利润。还包括广告投放、产品布局和行业报…