JVM类加载机制和双亲委派

news2025/1/20 5:45:44

类加载机制

java文件需要编译成字节码文件(.class文件),jvm是通过类加载机制,将.class文件加载进内存,经过验证连接->初始化直到使用该对象的过程就是类加载机制,当new对象的时候,jvm首先去常量池寻找该类的符号引用,找不到此引用,则执行类加载,简而言之就是jvm通过类加载器加载.class文件变成对象的过程就是类加载机制

三个重要的内置ClassLoader 

  • BootstrapClassLoader(启动类加载器(根)加载器) 负责加载\lib下的类库加载进内存,用来加载java的核心库
  • ExtensionClassLoader (扩展类加载器) 负责加载lib/ext或者由java.ext.dirs系统属性指定的目录中的JAR包的类
  • AppClassLoader (应用类加载器) 加载 Classpath 环境变量里定义的路径中的 jar 包和目录,继承自ClassLoader抽象类,所以自定义加载器也需要继承此接口,并重写findClass方法
 protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
 }

自定义类加载器

自定义加载器继承自ClassLoader,重写findClass方法

package com.alibaba.fescar.core.protocol.test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class MyDefineClassLoader extends ClassLoader {

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            // 读取字节数据
            Path path = Paths.get("D:\\601\\acm601\\cldm_springcloud\\wsd-common\\src\\main\\java\\com\\alibaba\\fescar\\core\\protocol\\test\\TestClass.class");
            byte[] classData = Files.readAllBytes(path);
            // 将字节码内容转换为Class对象
            return defineClass(name, classData, 0, classData.length);
        } catch (IOException e) {
           throw new ClassNotFoundException("Class not found: " + name, e);
        }

    }
}

定义测试类,并生成.class文件

package com.alibaba.fescar.core.protocol.test;

public class TestClass {

    public void testClassLoader(){
        System.out.println("test my define classloader");
    }
}

自定义类加载器的使用 

package com.alibaba.fescar.core.protocol.test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        MyDefineClassLoader myDefineClassLoader = new MyDefineClassLoader();
        // 加载测试类生成Class对象 一定要带包名
        Class<?> testClass = myDefineClassLoader.loadClass("com.alibaba.fescar.core.protocol.test.TestClass");
        // 使用反射获得对象
        Object o =testClass.getDeclaredConstructor().newInstance();
        Method testClassLoader = testClass.getMethod("testClassLoader");
        // 调用方法
        testClassLoader.invoke(o);
    }
}

运行结果如下 

类加载的过程 

  • 加载阶段(将.class文件加载进内存)
  • 验证、准备、解析阶段(验证.class文件的正确性 准备(为类变量(静态变量)分配内存和初始化默认值)解析(将常量池池中的符号引用转化为直接引用))
  • 初始化阶段(执行类构造器init)

加载阶段 

 将.class字节码文件的二进制数据读入内存中,然后将这些数据翻译成类的元数据,元数据包括方法代码,变量名,方法名,访问权限与返回值,接着将元数据存入方法区,最后会在堆中创建一个Class对象

.class文件读入内存——>元数据放进方法区——>Class对象放进堆中

验证、准备、解析阶段 

验证被加载类的正确性与安全性,看class文件是否正确,是否对会对虚拟机造成安全问题等,主要去验证文件格式与符号引用等

对整个类加载机制而言,验证阶段是一个很重要但是非必需的阶段,毕竟验证需要花费一定的的时间,可以使用-Xverfity:none来关闭大部分的验证

准备 在这个阶段中,主要是为类变量(静态变量)分配内存以及初始化默认值,因为静态变量全局只有一份,是跟着类走的,因此分配内存其实是在方法区上分配。

  • 在准备阶段,虚拟机只为静态变量分配内存,实例变量要等到初始化阶段才开始分配内存
  • 为静态变量初始化默认值,是初始化对应数据类型的默认值,不是自定义的值
  • 被final修饰的静态变量,如果值比较小,则在编译后直接内嵌到字节码中。如果值比较大,也是在编译后直接放入常量池中。准备阶段结束后,final类型的静态变量已经有了用户自定义的值,而不是默认值

 解析阶段,主要是将class文件中常量池中的符号引用转化为直接引用

 符号引用:可以直接理解为是一个字符串,用这个字符串来表示一个目标

 直接引用:直接引用是一个指向目标的指针,能够通过直接引用定位到目标

Logger logger = new Logger();

我们可以通过引用变量logger直接定位到新创建出的Logger 对象实例,将符号引用转化为直接引用,就能将字符串logger转化为指向对象的指针

 初始化阶段

初始化,就是虚拟机执行类构造器<clinit>方法的过程,<clinit>方法是由编译器自动去搜集类中的所有类变量与静态语句块合并产生的。可能存在多个线程同时执行某个类的<clinit>()方法,虚拟机此时会对该方法进行加锁,保证只有一个线程能执行

在此阶段类变量与类成员变量才会被赋予用户自定义的值,只有在初始化阶段完成后,类才能被正常使用

初始化顺序 

父类的静态域->子类的静态域->父类的非静态域->子类的非静态域->父类的构造方法->子类的构造方法

静态域包括静态变量与静态代码块,静态变量和静态代码块的执行顺序由编码顺序决定

静态先于非静态,父类先于子类,构造方法在最后

双亲委派机制

java虚拟机中有多个类加载器,双亲委派机制的核心是解决一个类到底由谁加载的问题,针对的是类加载器(ClassLoader),避免了类的重复加载

当一个类加载器收到了一个类加载请求时,它自己不会先去尝试加载这个类,而是把这个请求转交给父类加载器,每一个层的类加载器都是如此,因此所有的类加载请求都应该传递到最顶层的启动类加载器中。只有当父类加载器在自己的加载范围内没有搜寻到该类时,并向子类反馈自己无法加载后,子类加载器才会尝试自己去加载

如果一个类重复出现在三个类加载器的加载位置,应该由启动类加载器(根加载器)加载,因为根据双亲委派机制,它的优先级是最高的 

打破双亲委派 

打破双亲委派机制的主要原因是为了满足一些特定的需求和场景:

  • 实现类的热部署:在某些应用场景下,需要在运行时动态加载和替换类,以实现热部署的功能。而双亲委派机制会导致类的加载只发生一次,无法实现类的热替换
  • 加载非标准的类文件:有些特殊的类文件,如动态生成的字节码、非标准的类文件格式等,无法通过标准的类加载器加载
  • 实现类加载的动态控制:有些应用需要对类的加载进行特殊的控制,例如对特定的类进行加密、解密或验证等操作

打破双亲委派的方法 

自定义类加载器 通过自定义ClassLoader的子类,重写findClass()方法,实现自定义的类加载逻辑,不委托给父类加载器,从而打破双亲委派机制

使用Java动态代理 Java动态代理机制可以在运行时生成代理类,并在代理类中实现特定的逻辑。通过使用动态代理,可以在类加载时动态生成代理类,从而打破双亲委派机制

线程上下文类加载器通过Thread类的setContextClassLoader()方法,可以设置线程的上下文类加载器,从而打破双亲委派机制

当然还有其他方法和框架打破双亲委派,比如OSGi框架、动态代理框架等

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

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

相关文章

try…except语句

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在程序开发时&#xff0c;有些错误并不是每次运行都会出现。例如&#xff0c;实例01&#xff0c;只要输入的数据符合程序的要求&#xff0c;程序就可…

外汇天眼:Marqeta加速欧洲业务发展,华沙办公室正式开幕

Marqeta&#xff0c;全球现代卡发行平台&#xff0c;今天宣布在波兰华沙设立新办公室&#xff0c;以支持其长期的业务和增长战略。通过在波兰设立业务&#xff0c;Marqeta直接获得了进入欧盟的通道&#xff0c;为其在跨境增长和提供增强服务奠定了良好基础。波兰作为欧洲中心位…

代码随想录算法训练营第十三天| 102. 二叉树的层序遍历、226.翻转二叉树、101. 对称二叉树

102. 二叉树的层序遍历 题目链接&#xff1a;102. 二叉树的层序遍历 文档讲解&#xff1a;代码随想录 状态&#xff1a;dfs没写出来&#xff0c;bfs不知道如何分层 import java.util.*;public class BinaryTreeLevelOrderTraversal {// 用于存储每一层的节点值List<List<…

大数据之Schedule调度错误(一)

当我们在利用ooize发起整个任务的调度过程中,如果多个调度任务同时运行并且多个调度任务操作了相同的表,那么就会出现如下的错误关系: Invalid path hdfs://iZh5w01l7f8lnog055cpXXX:8000/user/admin/xxx: No files matching path hdfs://iZh5w01l7f8lnog055cpXXX:8000/user/ad…

MySQL—函数(介绍)—字符串函数(基础)

一、引言 提到函数&#xff0c;在SQL分类中DQL语句中有一个聚合函数&#xff0c;如COUNT()、SUM()、MAX()等等。这些都是一些常见的聚合函数&#xff0c;而聚合函数只是函数的一种&#xff0c;接下来会详细的学习和介绍一下函数的应用场景和以及 mysql 当中文件的函数有哪些。 …

JAVA小案例-用循环语句输出1-1000以内能被5整除的数,每5个一行

JAVA小案例-用循环语句输出1-1000以内能被5整除的数&#xff0c;每5个一行 直接看代码&#xff1a; public class Zhengchu {/*** 用循环语句输出1-1000以内能被5整除的数&#xff0c;每5个一行** param args*/public static void main(String[] args) {for (int i 1; i <…

HTML 转义字符(escape characters)及其对应的符号(symbols)

以下是常见的 HTML 转义字符及其对应的符号&#xff0c;这些可以用于在 HTML 或 JSX 中避免解析错误和特殊字符的冲突&#xff1a; 空格 ( ): 或 引号: 单引号&#xff08;&#xff09;&#xff1a;&apos;、&lsquo;、、&rsquo;双引号&#xff08;"&#x…

GPS定位器专用可编程晶振SG-8018CB

随着全球定位系统&#xff08;GPS&#xff09;技术的普及&#xff0c;GPS定位器在各种领域中得到了广泛应用&#xff0c;如车辆跟踪、个人定位、资产管理和户外活动等。为了确保GPS定位器的高精度和可靠性&#xff0c;选择合适的时钟源至关重要。SG-8018CB可编程晶振作为一款高…

Linux:基本指令

文章目录 ls指令pwd指令cd指令touch指令mkdir指令rmdir指令 && rm指令cp指令man指令echo指令输出重定向追加重定向 cat指令输入重定向 mv指令which指令alias指令more && less指令head && tail指令事件相关的指令date显示时间戳 cal指令find指令grep指令…

十三、resultMap解析

分为两部分&#xff1a;解析和使用 解析 1.解析XML的时候单独解析所有的resultMap标签&#xff0c;封装成ResultMap对象存入configuration中 2.解析XML中的SQL语句&#xff0c;封装MappedStatement对象&#xff0c;这里会根据SQL的返回类型是resultMap还是resultType做处理。如…

乡村振兴与乡村旅游品牌化:打造具有地方特色的乡村旅游品牌,提升乡村旅游吸引力,促进美丽乡村建设

目录 一、引言 二、乡村旅游品牌化的重要性 &#xff08;一&#xff09;增强乡村旅游的辨识度 &#xff08;二&#xff09;提升乡村旅游的附加值 &#xff08;三&#xff09;促进乡村文化的传承与创新 三、打造具有地方特色的乡村旅游品牌 &#xff08;一&#xff09;明…

人工智能与能源约束的矛盾能否化解

以下文章来源&#xff1a;澎湃新闻 人工智能技术在台前展示的是比特世界的算力、算法和数据&#xff0c;但其“轻盈的灵魂”背后则是土地、能源和水等物理世界“沉重的肉身”。根据本文三种情境的模拟测算&#xff0c;未来人工智能发展需要可持续的巨量能源支撑&#xff0c;能源…

使用 NVIDIA NIM 部署生成式 AI 的简单指南

使用 NVIDIA NIM 部署生成式 AI 的简单指南 无论您是在本地还是在云端工作&#xff0c;NVIDIA NIM 推理微服务都可以为企业开发人员提供来自社区、合作伙伴和 NVIDIA 的易于部署的优化 AI 模型。作为 NVIDIA AI Enterprise 的一部分&#xff0c;NIM 提供了一条安全、简化的前进…

Excel 每 N 行拼成一行

F列每四行对应一条记录&#xff1a; ABCDEF1NameAddressCityShort IDCompany 122222 al street3Blue cheese415Company 261111 arm rd7Ranch829Company 3103333 raindrop drive11Peanut123 需要把F列整理成规范表格&#xff0c;按行写入A-D&#xff1a; ABCDEF1NameAddressC…

python中return语句的用法

一、了解函数的标准格式 def 函数名(参数1, 参数2, ...&#xff0c;参数n):函数体第一行代码函数体第二行代码函数体第三行代码...return 语句变量 函数名(参数1&#xff0c;参数2&#xff0c;...&#xff0c;参数n) python遇到return语句时&#xff0c;会结束整个函数调用&a…

VS2017配置OpenCV4.5.1

VS2017配置OpenCV 一、下载OpenCV二、配置OpenCV的电脑环境变量三、配置visual Studio添加路径复制文件到C盘 四、如何使用注意运行时选择Debug x64 五、报错&#xff1a;VSOpencv出现&#xff1a;xxx处有未经处理的异常: Microsoft C 异常: cv::Exception&#xff0c;位于内存…

OBS+nginx+nginx-http-flv-module实现阿里云的推流和拉流

背景&#xff1a;需要将球机视频推送到阿里云nginx&#xff0c;使用网页和移动端进行播放&#xff0c;以前视频格式为RTMP&#xff0c;但是在网页上面播放RTMP格式需要安装flash插件&#xff0c;chrome浏览器不给安装&#xff0c;调研后发现可以使用nginx的模块nginx-http-flv-…

剪画小程序:AI声音克隆,只需10秒完美复制真人音色

Hello&#xff0c;大家好呀&#xff01;我是分享声音的克隆。 想象一下&#xff0c;如果你能够复制自己的声音&#xff0c;那么您可以给视频配上自己的声 音&#xff0c;那是多么的有趣啊。 ​编辑 工具&#xff1a;小程序剪画 功能简介&#xff1a;支持多种端口&#xff1…

任务3.3 学生喂养三种宠物:猫、狗和鸟

本任务旨在通过Java面向对象编程中的多态性和方法重载概念&#xff0c;实现一个学生喂养三种不同宠物&#xff08;猫、狗、鸟&#xff09;的程序。 定义基类和派生类 创建一个Animal基类&#xff0c;包含所有动物共有的属性和方法&#xff0c;如name、age、speak()、move()和ea…

自然语言处理(NLP)—— C-value方法

自然语言处理&#xff08;NLP&#xff09;和文本挖掘是计算机科学与语言学的交叉领域&#xff0c;旨在通过计算机程序来理解、解析和生成人类语言&#xff0c;以及从大量文本数据中提取有用的信息和知识。这些技术在现代数据驱动的世界中扮演着关键角色&#xff0c;帮助我们从海…