【JVM】详解双亲委派机制

2024-06-18 13:04

本文主要是介绍【JVM】详解双亲委派机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

双亲委派机制是Java类加载器的一种工作模式,确保类加载的一致性和安全性。以下是详细的定义、优缺点以及如何破坏双亲委派机制的描述。

双亲委派机制的定义

双亲委派机制(Parent Delegation Model)是一种类加载器的工作模式。在这种模式下,类加载器在加载类时,会先将加载请求委派给父类加载器处理,只有当父类加载器无法完成类加载时,子类加载器才会尝试加载该类。

双亲委派机制的工作过程:
  1. 检查缓存:类加载器首先检查是否已经加载过该类,如果已经加载过,则直接返回该类。
  2. 委派父加载器:如果没有加载过该类,类加载器将加载请求委派给父类加载器。
  3. 递归过程:父类加载器也按照相同的过程处理加载请求,直到委派到启动类加载器(Bootstrap ClassLoader)。
  4. 启动类加载器加载:启动类加载器尝试加载类,如果加载成功,则返回该类,否则继续步骤5。
  5. 逐级回退:如果启动类加载器无法加载该类,加载请求逐级回退到下一级类加载器,直至回退到最初的请求者。
  6. 自行加载:最终,如果所有父类加载器都无法加载该类,子类加载器才会尝试自行加载。

双亲委派机制的优点

  1. 安全性:双亲委派机制确保了核心类库(如java.lang.*包)不会被重复加载和篡改。只有启动类加载器能加载这些核心类库,避免了安全风险。
  2. 避免类重复加载:通过委派机制,保证了类只会被加载一次,从而节省内存,提高性能。
  3. 一致性:同一个类在整个Java应用中只有一个唯一的定义,避免了同名类不同实现的冲突问题。

双亲委派机制的缺点

  1. 灵活性不足:双亲委派机制的严格层级关系使得子类加载器很难绕过父类加载器直接加载类,这在某些情况下限制了灵活性。
  2. 复杂性:实现自定义类加载器时,需要理解和实现双亲委派机制,这增加了开发的复杂性。

如何破坏双亲委派机制

破坏双亲委派机制通常是为了满足某些特定需求,如加载自定义的类或版本不同的类库。以下是一些破坏双亲委派机制的方法:

1. 自定义类加载器

通过继承ClassLoader并覆盖loadClass方法,可以实现不使用双亲委派机制的类加载器。

public class CustomClassLoader extends ClassLoader {@Overridepublic Class<?> loadClass(String name) throws ClassNotFoundException {// 不委派给父类加载器,直接加载类byte[] classData = getClassData(name);if (classData == null) {throw new ClassNotFoundException();}return defineClass(name, classData, 0, classData.length);}private byte[] getClassData(String className) {// 读取类文件的字节码String path = className.replace('.', '/') + ".class";try (InputStream is = getClass().getResourceAsStream(path)) {ByteArrayOutputStream byteStream = new ByteArrayOutputStream();int nextValue = 0;while ((nextValue = is.read()) != -1) {byteStream.write(nextValue);}return byteStream.toByteArray();} catch (IOException e) {e.printStackTrace();return null;}}
}
2. 使用不同的类加载器加载不同版本的类

通过不同的类加载器加载不同版本的类库,避免类库冲突。

public class VersionClassLoader extends ClassLoader {private String version;public VersionClassLoader(String version) {this.version = version;}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {String path = "/lib/" + version + "/" + name.replace('.', '/') + ".class";try (InputStream is = getClass().getResourceAsStream(path)) {if (is == null) {throw new ClassNotFoundException(name);}ByteArrayOutputStream byteStream = new ByteArrayOutputStream();int nextValue = 0;while ((nextValue = is.read()) != -1) {byteStream.write(nextValue);}byte[] classData = byteStream.toByteArray();return defineClass(name, classData, 0, classData.length);} catch (IOException e) {throw new ClassNotFoundException(name, e);}}
}
3. 重写findClass方法

通过重写ClassLoaderfindClass方法,自定义类加载逻辑,从而绕过父类加载器。

public class CustomFindClassLoader extends ClassLoader {@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {byte[] classData = getClassData(name);if (classData == null) {throw new ClassNotFoundException();}return defineClass(name, classData, 0, classData.length);}private byte[] getClassData(String className) {String path = className.replace('.', '/') + ".class";try (InputStream is = getClass().getResourceAsStream(path)) {ByteArrayOutputStream byteStream = new ByteArrayOutputStream();int nextValue = 0;while ((nextValue = is.read()) != -1) {byteStream.write(nextValue);}return byteStream.toByteArray();} catch (IOException e) {e.printStackTrace();return null;}}
}

总结

双亲委派机制通过递归委派机制确保了Java类加载的安全性、一致性和性能。但是,为了满足某些特定需求,有时需要破坏这一机制。通过自定义类加载器并覆盖loadClassfindClass方法,可以实现不依赖双亲委派机制的类加载逻辑。尽管如此,在破坏双亲委派机制时应谨慎操作,以避免潜在的类加载冲突和安全问题。

这篇关于【JVM】详解双亲委派机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1072066

相关文章

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.

mac中资源库在哪? macOS资源库文件夹详解

《mac中资源库在哪?macOS资源库文件夹详解》经常使用Mac电脑的用户会发现,找不到Mac电脑的资源库,我们怎么打开资源库并使用呢?下面我们就来看看macOS资源库文件夹详解... 在 MACOS 系统中,「资源库」文件夹是用来存放操作系统和 App 设置的核心位置。虽然平时我们很少直接跟它打交道,但了

Spring MVC如何设置响应

《SpringMVC如何设置响应》本文介绍了如何在Spring框架中设置响应,并通过不同的注解返回静态页面、HTML片段和JSON数据,此外,还讲解了如何设置响应的状态码和Header... 目录1. 返回静态页面1.1 Spring 默认扫描路径1.2 @RestController2. 返回 html2

关于Maven中pom.xml文件配置详解

《关于Maven中pom.xml文件配置详解》pom.xml是Maven项目的核心配置文件,它描述了项目的结构、依赖关系、构建配置等信息,通过合理配置pom.xml,可以提高项目的可维护性和构建效率... 目录1. POM文件的基本结构1.1 项目基本信息2. 项目属性2.1 引用属性3. 项目依赖4. 构

Rust 数据类型详解

《Rust数据类型详解》本文介绍了Rust编程语言中的标量类型和复合类型,标量类型包括整数、浮点数、布尔和字符,而复合类型则包括元组和数组,标量类型用于表示单个值,具有不同的表示和范围,本文介绍的非... 目录一、标量类型(Scalar Types)1. 整数类型(Integer Types)1.1 整数字

Spring常见错误之Web嵌套对象校验失效解决办法

《Spring常见错误之Web嵌套对象校验失效解决办法》:本文主要介绍Spring常见错误之Web嵌套对象校验失效解决的相关资料,通过在Phone对象上添加@Valid注解,问题得以解决,需要的朋... 目录问题复现案例解析问题修正总结  问题复现当开发一个学籍管理系统时,我们会提供了一个 API 接口去