JVM—类加载子系统

JVM—类加载子系统

JVM的类加载是通过ClassLoader及其子类来完成的。

有哪些类加载器

类加载器如下:

类加载器

  • 启动类加载器(BootStrap ClassLoader):负责加载JAVA_HOME\lib目录或通过-Xbootclasspath参数指定路径中的且被虚拟机认可(rt.jar)的类库;
  • 扩展类加载器(Extension ClassLoader):负责加载JAVA_HOME\lib\ext目录或通过java.ext.dirs系统变量指定路径中的类库;
  • 应用程序类加载器(Application ClassLoader):负责加载用户路径classpath上的类库;
  • 自定义类加载器(Custom ClassLoader):加载应用之外的类文件;

类加载器执行顺序

类加载器执行顺序如下图:

类加载器执行顺序

  1. 自底向上检查类是否已经加载:

    加载过程中会先检查类是否已被加载,从自定义加载器到BootStrap逐层检查,只要某个类加载器已加载某个类,就视为此类已加载,可以保证此类使得所有ClassLoader只加载一次;

  2. 自顶向下尝试加载类:由上层来逐层尝试加载此类。

类加载时机与过程

类加载的四个时机:

  1. 遇到new、getStatic、putStatic、invokeStatic四条指令;

    比如有如下类:

    public class MyTest {
        public static int hello;
        
        public static void testMethod(){
            
        }
    }
    

    当使用如下三种代码时,此类会被加载:

    //第一种
    MyTest.age;
    //第二种
    MyTest.testMethod();
    //第一种
    new MyTest();
    
  2. 使用java.lang.reflect包方法对类进行反射调用;

    比如:

    Class clazz = Class.forName("com.sjdwz.MyTest");
    
  3. 初始化一个类,发现其父类还没初始化,要先初始化其父类;

  4. 当虚拟机启动时,用户需要指定一个主类main,需要先将主类加载。

一个类的一生

一个类的一生如下:

一个类的一生

类加载做了什么

主要做了三件事:

  1. 根据类全限定名称,定位到class文件,以二进制字节流形式加载到内存中;
  2. 把字节流静态数据加载到方法区(永久代,元空间);
  3. 基于字节流静态数据,创建字节码Class对象。

类加载途径

类加载途径如下图:

类加载途径

自定义类加载器

我们可以自定义类加载器,来加载D:\sjdwzTest目录下的lib文件夹下的类。

步骤如下:

  1. 新建一个类MyTest.java

    package com.sjdwz.myclassloader;
    public class MyTest {
        public void sayHello(){
            System.out.println("hello world!");
        }
    }
    
  2. 使用javac MyTest.java命令,将生成的MyTest.class文件放到D:\sjdwzTest\lib\com\sjdwz\myclassloader文件夹下

    注意:包路径不能错。

    编译的位置

  3. 自定义类加载器,继承ClassLoader,重写findClass()方法 ,调用defineClass()方法:

    /**
     * @Description 自定义类加载器
     * @Created by 随机的未知
     */
    public class SjdwzClassLoader extends ClassLoader {
        private String classpath;
    
        public SjdwzClassLoader(String classpath) {
            this.classpath = classpath;
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                //输入流,通过类的全限定名称加载文件到字节数组
                byte[] classDate = getData(name);
                if (classDate != null) {
                    //defineClass方法将字节数组数据 转为 字节码对象
                    return defineClass(name, classDate, 0, classDate.length);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return super.findClass(name);
        }
    
        /**
         * 加载类的字节码数据
         * @param className
         * @return
         * @throws IOException
         */
        private byte[] getData(String className) throws IOException{
            String path = classpath + File.separatorChar +
                    className.replace('.', File.separatorChar) + ".class";
            try (InputStream in = new FileInputStream(path);
                 ByteArrayOutputStream out = new ByteArrayOutputStream()) {
                byte[] buffer = new byte[2048];
                int len = 0;
                while ((len = in.read(buffer)) != -1) {
                    out.write(buffer, 0, len);
                }
                return out.toByteArray();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
  4. 测试类如下:

    public class SjdwzClassLoaderTest {
        public static void main(String[] args) throws Exception {
            //自定义类加载器的记载路径
            SjdwzClassLoader sjdwzClassLoader = new SjdwzClassLoader("D:\\sjdwzTest\\lib");
            Class<?> testClazz = sjdwzClassLoader.loadClass("com.sjdwz.myclassloader.MyTest");
            if(testClazz != null){
                Object testObj = testClazz.newInstance();
                Method sayHelloMethod = testClazz.getMethod("sayHello", null);
                sayHelloMethod.invoke(testObj,null);
                System.out.println(testClazz.getClassLoader().toString());
            }
        }
    }
    

    输出如下:

    输出

双亲委派与打破双亲委派

什么是双亲委派

当一个类加载器收到类加载任务,会先交给其父类加载器去完成。 因此,最终加载任务都会传递到顶层的启动类加载器,只有当父类加载器无法完成加载任务时,子类才会尝试加载任务。

为什么需要双亲委派

主要考虑安全因素,双亲委派可以避免重复加载核心的类,当父类加载器已经加载了该类时,子类加载器不会再去加载。

为什么还需要破坏双亲委派

在实际应用中,双亲委派解决了Java基础类统一加载的问题,但是存在着缺陷。JDK中的基础类的方法作为典型的API被用户类用户调用,但是也存在API调用用户代码的情况,比如:SPI代码。这种情况就需要打破双亲委派模式。

比如:数据库驱动DriverManager。以Driver接口为例,Driver接口定义在JDK中,其实现由各个数据库的服务商来提供,由系统类加载器加载。这个时候就需要启动类加载器来委托子类来加载Driver实现,这就破坏了双亲委派。

如何破坏双亲委派

  1. 重写ClassLoader的loadClass方法;

    在JDK1.2之后,新加了一个findClass方法让用户重写;

  2. SPI,父类委托子类加载器加载Class;

  3. 热部署和不停机更新用到的OSGI技术。

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

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

相关文章

Linux|centos7|postgresql数据库主从复制之异步还是同步的问题

前言&#xff1a; postgresql数据库是一个比较先进的中型关系型数据库&#xff0c;原本以为repmgr和基于repmgr的主从复制是挺简单的一个事情&#xff0c;但现实很快就给我教育了&#xff0c;原来postgresql和MySQL一样的&#xff0c;也是有异步或者同步的复制区别的 Postgre…

物联网实战--入门篇之(十)安卓QT--后端开发

目录 一、项目配置 二、MQTT连接 三、数据解析 四、数据更新 五、数据发送 六、指令下发 一、项目配置 按常规新建一个Quick空项目后&#xff0c;我们需要对项目内容稍微改造、规划下。 首先根据我们的需要在.pro文件内添加必要的模块&#xff0c;其中quick就是qml了&…

Springboot集成knife4j (swagger)

1、添加依赖 在pom.xml 文件中添加 knife4j-spring-boot-starter 的依赖 <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>3.0.3</version> </depe…

TCP、UDP协议

TCP与UDP协议的区别 TCP&#xff08;Transmission Control Protocol&#xff09;和UDP&#xff08;User Datagram Protocol&#xff09;是两种常用的传输层协议&#xff0c;它们之间有以下几点区别&#xff1a; 1. 连接性&#xff1a; - TCP是面向连接的协议&#xff0c;通…

玩转ChatGPT:Kimi测评(科研写作)

一、写在前面 ChatGPT作为一款领先的语言模型&#xff0c;其强大的语言理解和生成能力&#xff0c;让无数用户惊叹不已。然而&#xff0c;使用的高门槛往往让国内普通用户望而却步。 最近&#xff0c;一款由月之暗面科技有限公司开发的智能助手——Kimi&#xff0c;很火爆哦。…

VMware-16.0配置虚拟机网络模式

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、为什么要配置网络&#xff1f;二、配置步骤1.检查VMware服务2.进入配置页面3.添加网络模式1.Bridge2.NAT3.Host-only 4.DHCP租约5.静态IP 三、使用总结 前言…

wife_wife【web 攻防世界】

大佬的wp:WEB&#xff1a;Wife_wife-CSDN博客 知识点&#xff1a; prototype是new class 的一个属性&#xff0c;即__proto__指向new class 的prototype属性__proto__如果作为json代码解析的话会被当成键名处理&#xff0c;但是如果是在类中的话则会被当成子类的原型 如let o…

OpenCV 4.9基本绘图

返回&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV使用通用内部函数对代码进行矢量化 下一篇&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; ​目标 在本教程中&#xff0c;您将学习如何&am…

如何对Webpack进行优化

目录 1.优化-提取css代码 1.1. 插件 mini-css-extract-plugin 1.2. 步骤&#xff1a; 1.3. 注意 1.4. 好处 1.5. 练习 2. 优化-css代码提取后压缩 2.1. 问题引入 2.2. 解决 2.3. 步骤 3. Webpack打包less代码 3.1. 加载器 less-loader 3.2. 步骤 3.3. 注意&#xf…

【Redis 知识储备】应⽤数据分离架构 -- 分布系统的演进(2)

应⽤数据分离架构 随着系统的上线&#xff0c;我们不出意外地获得了成功。市场上出现了⼀批忠实于我们的⽤⼾&#xff0c;使得系统的访问量逐步上升&#xff0c;逐渐逼近了硬件资源的极限&#xff0c;同时团队也在此期间积累了对业务流程的⼀批经验。⾯对当前的性能压⼒&#x…

Android Studio学习8——点击事件

在xml代码中绑定 在java代码中绑定 弹出一个toast 随机&#xff0c;数组

基于Docker for Windows部署ChatGPT-Next-Web

基于Docker for Windows部署ChatGPT-Next-Web 项目地址安装Docker for Windows部署项目参数讲解参数示例 运行 项目地址 https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 安装Docker for Windows 官网地址&#xff1a;https://www.docker.com/ 下拉找到Download 选择W…

篮球竞赛预约平台的设计与实现|Springboot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)篮球馆,篮球赛,竞赛项目,赛事预约

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读300套最新项目持续更新中..... 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含ja…

数据库系统概论(超详解!!!) 第三节 关系数据库标准语言SQL(Ⅳ)

1.集合查询 集合操作的种类 并操作UNION 交操作INTERSECT 差操作EXCEPT 参加集合操作的各查询结果的列数必须相同;对应项的数据类型也必须相同 查询计算机科学系的学生及年龄不大于19岁的学生。SELECT *FROM StudentWHERE Sdept CSUNIONSELECT *FROM StudentWHERE Sage&l…

go之web框架gin

介绍 Gin 是一个用 Go (Golang) 编写的 Web 框架。 它具有类似 martini 的 API&#xff0c;性能要好得多&#xff0c;多亏了 httprouter&#xff0c;速度提高了 40 倍。 如果您需要性能和良好的生产力&#xff0c;您一定会喜欢 Gin。 安装 go get -u github.com/gin-gonic/g…

SpringBoot | Spring Boot“整合Redis“

目录: 1. Redis 介绍2. Redis 下载安装3. Redis “服务开启”和“连接配置”4. Spring Boot整合Redis的“前期准备” :① 编写实体类② 编写Repository 接口③ 在“全局配置文件”中添加 “Redis数据库” 的 “相关配置信息” 5. Spring Boot整合“Redis” (案例展示) 作者简介…

Golang | Leetcode Golang题解之第5题最长回文子串

题目&#xff1a; 题解&#xff1a; func longestPalindrome(s string) string {if s "" {return ""}start, end : 0, 0for i : 0; i < len(s); i {left1, right1 : expandAroundCenter(s, i, i)left2, right2 : expandAroundCenter(s, i, i 1)if ri…

使用fusesource的mqtt-client-1.7-uber.jar,mqtt发布消息出去,接收端看到的是中文乱码,如何解决?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

安全架构设计理论与实践相关知识总结

一、安全架构概述 常见信息威胁介绍&#xff1a; 1. 信息泄露&#xff1a;信息被泄露或透露给某个非授权实体 2. 破坏信息完整性&#xff1a;数据被非授权地进行增删改查货破坏而受到损失 3. 拒绝服务&#xff1a;对信息会其他资源的合法访问被无条件的组织 4. 非法使用&#x…

Linux网络编程二(TCP图解三次握手及四次挥手、TCP滑动窗口、MSS、TCP状态转换、多进程/多线程服务器实现)

文章目录 1、TCP三次握手(1) 第一次握手(2) 第二次握手(3) 第三次握手 2、TCP四次挥手(1) 一次挥手(2) 二次挥手(3) 三次挥手(4) 四次挥手 3、TCP滑动窗口4、TCP状态时序图5、多进程并发服务器6、多线程并发服务器 1、TCP三次握手 TCP三次握手(TCP three-way handshake)是TCP协…