你真的了解Java类加载机制吗?

news2024/10/7 12:25:28

大家好,我是小米,一个喜欢分享技术的程序员。今天我来给大家简述一下Java类加载模型。

 

在Java中,类的加载过程是在程序运行时动态进行的。Java的类加载模型可以分为三个步骤:加载、连接和初始化。

类加载过程:加载

首先是加载阶段,也就是将类的字节码加载到内存中。在Java中,有三种不同的类加载器:Bootstrap ClassLoader、Extension ClassLoader和Application ClassLoader。

  • Bootstrap ClassLoader是最顶层的类加载器,负责加载JRE的核心类库,如java.lang包中的类。
  • Extension ClassLoader负责加载Java的扩展类库。
  • Application ClassLoader则负责加载应用程序的类。

类加载过程:连接

接下来是连接阶段,也就是将加载的字节码转换为可执行的代码。连接阶段分为三个步骤:验证、准备和解析。

  • 在验证阶段,Java会对字节码进行验证,确保其符合Java虚拟机规范。
  • 在准备阶段,Java会为类的静态变量分配内存,并将其初始化为默认值。
  • 在解析阶段,Java会将符号引用解析为直接引用。

类加载过程:初始化

最后是初始化阶段,也就是执行类的构造函数,并执行静态变量的赋值操作。在Java中,类的初始化是线程安全的,因为只有一个线程会执行初始化操作。

什么是双亲委派模型

那么,什么是双亲委派模型呢?简单来说,就是在类加载时先由父类加载器去加载,如果父类加载器找不到该类,才由子类加载器去加载。这种模型的好处是可以保证Java程序的安全性和稳定性,因为如果父类加载器已经加载了一个类,子类加载器就不需要再加载一遍,避免了出现类似于同名类被重复加载的情况。但是,双亲委派模型也有一些缺点,例如无法实现对于同一个类的不同版本的加载,因为父类加载器会优先加载已经存在的类,导致子类加载器无法加载另一个版本的同名类。

为什么Tomcat要自定义类加载器

那么,为什么Tomcat要自定义类加载器呢?这是因为在Tomcat中,有多个Web应用程序需要加载自己的类库。如果使用Java默认的双亲委派模型,可能会导致同名类库被多个Web应用程序重复加载,浪费内存资源。所以,Tomcat使用自定义的类加载器来实现Web应用程序之间的隔离,确保每个Web应用程序只加载自己的类库。

案例分析

最后,我用一个电商项目实际的案例来演示自定义类加载器。假设我们有一个电商项目,其中包含了一个名为“Order”的类,我们需要在项目中同时使用两个版本的“Order”类,一个是1.0版本,一个是2.0版本。这时候,我们就可以自定义一个类加载器,通过指定不同的类加载路径,分别加载两个版本的“Order”类。具体实现代码如下:

 

在这个示例中,我们自定义了一个名为CustomClassLoader的类加载器,它接受一个classPath参数,表示要加载类的路径。在findClass方法中,我们首先通过loadClassData方法读取字节码文件,然后通过defineClass方法将字节码文件转换为Class对象返回。

为了演示如何加载两个版本的同名类,我们可以分别将两个版本的Order类放置于不同的路径中,然后分别使用两个CustomClassLoader实例加载它们。具体示例如下:

 

这样,我们就成功地通过自定义类加载器加载了两个版本的同名类,实现了类的隔离。

自定义类加载器的场景

除了Tomcat这种容器框架需要自定义类加载器之外,还有其他一些场景也可能需要自定义类加载器。下面列举一些常见的场景:

  • 插件化开发:是一种常见的开发模式,通过动态加载插件,可以使应用程序具有更强的可扩展性。在插件化开发中,通常会涉及到加载不同的插件,这就需要使用自定义类加载器来实现不同插件的隔离。自定义类加载器可以使插件之间相互独立,不会相互影响。
  • 热部署:在一些特殊场景下,可能需要对应用程序进行热部署,即在应用程序运行过程中替换某些类。为了实现热部署,需要使用自定义类加载器,可以在加载类时重新读取字节码文件,从而实现对类的更新。这种方式可以避免应用程序的重启,提高了应用程序的可用性。
  • 多版本控制:在一些应用程序中,可能需要同时使用多个版本的同名类。例如,在进行系统升级时,可能需要同时存在新旧两个版本的类,以保证系统的兼容性。为了实现多版本控制,需要使用自定义类加载器,可以将不同版本的类隔离开来,避免冲突。
  • 实现类似于Java EE容器的类加载器层次结构:在一个Web应用程序中,可以定义多个类加载器,每个类加载器负责加载特定类型的类,并且它们之间形成了一种父子关系。这样可以实现对不同类的隔离和管理。
  • 防止Java反序列化漏洞:Java序列化和反序列化可以用于将Java对象转换为字节流以及从字节流中还原Java对象。但是,Java序列化机制存在一些安全漏洞,攻击者可以通过反序列化来执行恶意代码。为了避免这种情况,可以使用自定义类加载器来限制反序列化操作只在特定的安全上下文中进行。
  • 加载非标准格式的类文件:有时候,我们可能需要加载非标准格式的类文件,如动态生成的类或嵌入式Java类等。这些类文件可能无法被标准的类加载器加载,这时候就需要自定义类加载器来加载这些类文件。

总之,自定义类加载器是一种非常有用的工具,可以在某些特殊场景下实现类的隔离和动态加载。虽然自定义类加载器的使用比较复杂,但只要掌握了其原理和使用方法,就可以为我们的应用程序带来更多的可能性。

END

如有疑问或者更多的技术分享,欢迎关注我的微信公众号“知其然亦知其所以然”!

 

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

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

相关文章

Android面试指南:谈谈你对Flutter的理解

一、Flutter简介 Flutter是由Google开发的一种基于Dar编程语言的移动应用开发框架。可以帮助开发在构建高性能、美观、灵活的应用程序,从而实现跨平台开发,适用于与Android、ios、web、windows、macOS和linux等多个平台。 二、学习Flutter有什么优势 …

Java EE企业级应用开发(SSM)第11章

第11章SSM框架 一.预习笔记 1.准备jar包(注意版本) Spring一套包 Springmvc两个 Mybatis一个 Spring整合mybatis一个 Jstl一个用于jsp显示数据 Mysql一个用于访问数据库 Gson一个用于返回json数据 2.准备配置文件web.xml applicationContext.xml…

MySQL Client

MySQL客户端很多,自身携带的一些客户端工具也需要了解,方便快速测试。 MySQL Shell MySQL Shell Commands。 执行SQL语句时,必须切换到SQL模式。Shell指令较少,同时可以使用Python \py模式。 MySQL Shell所有的命令后面不需要加…

TCP通道和共享链路通道

推送SDK为了适应不同的场景和需求,对于一些对消息及时性、可靠性、自定义性要求高的应用,如即时通讯、社交、游戏等,可能更倾向于使用TCP通道,对于一些对消息节省流量、耗电量、兼容性要求高的应用,如新闻、天气、股票…

【软件工程】自动化测试保证卓越软件工程能力(3)

测试目标定义 对照目标系统,如下: 给出自动化测试平台目标如下: Case levelCase briefReport send toOVERALLUser 1 -> Process -> Customer 1BossLevel 1User 1 -> Process -> Customer 1 User 1 -> Process -> Custome…

AI自动写文章工具-ai文章智能生成器

随着人工智能技术的快速发展,越来越多的应用开始使用AI自动生成文章的功能,实现全自动、高质量和高效率的文章写作。本文将从全自动批量生成、没有错别字和标准语法、自动插入图片以及严格按照标准格式结构生成几个方面,展开对AI自动生成文章…

数据分析04——Pandas简介/Series对象/DataFrame对象

1、Pandas简介: Pandas是基于NumPy开发的数据分析三大剑客之一,Python数据分析的核心库提供快速、灵活、明确的数据结构Series对象:一维数组结构,由index和value构成DataFrame对象:二维数组结构,由index、…

MySQL基础(二十五)InnoDB数据存储结构

1 数据库的存储结构:页 索引结构给我们提供了高效的索引方式,不过索引信息以及数据记录都是保存在文件上的,确切说是存储在页结构中。另一方面,索引是在存储引擎中实现的,MySQL服务器上的存储引擎负责对表中数据的读取和写入工作…

在外Windows公网远程连接MongoDB数据库

文章目录 前言1. 安装数据库2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射2.3 测试随机公网地址远程连接 3. 配置固定TCP端口地址3.1 保留一个固定的公网TCP端口地址3.2 配置固定公网TCP端口地址3.3 测试固定地址公网远程访问 转载自远程内网穿透的文章:公网远…

友元函数,友元类,内部类及其之间的关系,匿名对象等

TIPS 当某一个类当中有自定义类型成员变量的时候,然后对该类的实例化对象调用函数的时候走初始化列表的时候,如果说要对自定义类型成员变量进行初始化列表初始化的时候,尽管那个自定义类型它的构造函数是没有参数的,但是此时括号…

数据剖析更灵活、更快捷,火山引擎 DataLeap 动态探查全面升级

更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群 近期,火山引擎 DataLeap 上线“动态探查”能力,为用户提供全局数据视角、完善的抽样策略,提高数据探查的灵活度以及响应速率。 …

【STL模版库】string类:模拟实现string类

一、成员变量 private:char *_str;size_t _size;size_t _capacity;public:static size_t npos -1; //编译报错,不能在类中初始化const static size_t npos -1; //[1]const char* c_str() const{ //[2]return _str;}size_t size() const{return _size;} size_t ca…

智慧水务云平台助力“十四五”水安全保障规划!

一、《“十四五”水安全保障规划》 水利部印发《“十四五”水安全保障规划》,规划中指出,“十四五”期间要抓好8个方面重点任务。 一是实施国家节水行动,强化水资源刚性约束。 二是加强重大水资源工程建设,提高水资源优化配置能…

Mongo执行计划explain分析

3.0+的explain有三种模式,分别是:queryPlanner、executionStats、allPlansExecution。现实开发中,常用的是executionStats模式。 1.使用方式 在查询语句后面加上explain("executionStats") db.user.find({"roleCodes":"xsbj","status&…

详细操作Selenium自动化测试之中的断言

Selenium常用的断言包括 页面属性断言:断言标题、url或页面源码中是否包含或不包含特定字符元素存在断言:断言指定元素存在图片及链接断言:断言图片正常显示、链接可以正常打开 页面属性断言 这是最常用的断言方式,可以用来断言…

TTL转HDMI 1.4,性能提升,pin to pin 芯片LT8618SXB

1. 描述 LT8618SX 是 Lontium 的低功耗版本 HDMI 发射器,其基于 ClearEdgeTM 技术。它支持 24 位色深 HDMI 1.4(高清多媒体接口)规范。它们与 Lontium 的第一代 HDMI 发射器 LT8618EX 完全向后兼容。 LT8618SX 是一款高性能、低功耗器件…

干货分享!9大Python常用技巧!

介绍 Python 炫酷功能(例如,变量解包,偏函数,枚举可迭代对象等)的文章层出不穷。但是还有很多 Python 的编程小技巧鲜被提及。因此,本文会试着介绍一些其它文章没有提到的小技巧,这些小技巧也是…

csgo搬砖项目,时间自由,项目包下车,包落地

Steam是一款全球较大的综合性数字游戏软件发行平台。steam同时在线飙到3300万!超越你说熟悉的王者,吃鸡!用户多,竞争者少,连我自己都没想到,有一天我居然可以靠着steam游戏搬砖来赚钱养活自己。 实话实说&a…

计算机基础--->数据结构(1)【图的存储和遍历】

文章目录 图图的存储图的搜索(无向无权图)代码演示 图 图中包含 顶点、边、度,无向图,有向图,无权图,带权图,其中 度表示一个顶点包含多少条边,有出度和入度。 图的存储 邻接矩阵 代…

【LeetCode】13,罗马数字转整数。 难度等级:简单。知识点:map和unordered_map的区别

文章目录 一、题目二、初级解法:顺序遍历字符串我的解法(语法平平无奇)语法接近 三、精妙解法:逆序遍历字符串四、知识点:map和unordered_map的区别 LeetCode 第13题,罗马数字转整数;难度等级&a…