首页 > 其他分享 >类加载器和双亲委派机制

类加载器和双亲委派机制

时间:2024-08-03 14:24:36浏览次数:10  
标签:委派 自定义 应用程序 线程 双亲 加载

什么是类加载器?

类加载器是Jvm的重要组成之一(类加载器、运行时数据区、执行引擎、本地库接口、本地方法库),负责读取java字节码并将其加载到Jvm中的组件

类加载器的分类

Java中的类加载器可以分为以下几种:

1. 启动类加载器(Bootstrap ClassLoader)

  • 定义:这是最顶层的类加载器,用于加载Java核心类库(如java.lang.*java.util.*等)。
  • 实现:启动类加载器是由本地代码(通常是C/C++)实现的,并不是一个Java类。
  • 加载路径:它加载位于<JAVA_HOME>/lib目录下的类文件。

2. 扩展类加载器(Extension ClassLoader)

  • 定义:用于加载扩展类库(通常是标准类库的扩展)。
  • 实现:由sun.misc.Launcher$ExtClassLoader类实现。
  • 加载路径:它加载位于<JAVA_HOME>/lib/ext目录下的类文件,或者由java.ext.dirs系统属性指定的路径。

3. 应用程序类加载器(Application ClassLoader)

  • 定义:又称为系统类加载器(System ClassLoader),用于加载应用程序的类文件。
  • 实现:由sun.misc.Launcher$AppClassLoader类实现。
  • 加载路径:它加载由CLASSPATH环境变量或java.class.path系统属性指定的路径中的类文件。

4. 自定义类加载器(Custom ClassLoader)

  • 定义:自定义类加载器是由开发者定义的类加载器,用于从特定来源加载类文件。通过自定义类加载器,可以实现从文件系统、网络、数据库等非标准路径加载类文件。
  • 实现:自定义类加载器通常通过继承java.lang.ClassLoader类并重写其方法来实现。例如,重写findClass方法来定义类的加载逻辑。
  • 加载路径:自定义类加载器可以从任何指定的路径加载类文件,这取决于自定义的实现逻辑。

类加载器的双亲委派模型

Java采用了双亲委派模型(Parent Delegation Model)来管理类加载器的层次结构。在这种模型中,每个类加载器在尝试加载类之前,会先委派给它的父类加载器加载。只有当父类加载器无法找到该类时,子加载器才会尝试加载。

例如当一个自定义类加载器试图加载一个类,它会先委派应用程序类加载器,如何应用程序类加载器会委派扩展类加载器,扩展类加载器会委派启动类加载器,启动类加载器先看一下自己有没有这个类,没有就让扩展类去加载,有的话直接自己加载,同理,扩展类也会先看有没有,没有的话让应用程序类加载,应用程序类也是同理。假如所有类加载器都没有该类,则会抛出ClassNotFoundException异常。

如图,自定义类加载器的父类加载器通常是应用程序类加载器(可改),应用程序的父类加载器是扩展类加载器,扩展类加载器的父类加载器是启动类加载器。值得一提的是,父类加载器是用类种的一个成员变量(parent)存储的,而因为启动类加载器特俗的地位和职责,无法在java中获取到,所以实际上扩展类加载器的parent存放的是一个null,实际需要调用启动类加载器时会通过特殊的方法实现。通过getClassLoader()方法去获得启动类加载器返回的也是null。

双亲委派模型的好处

  1. 安全性:防止核心类库被自定义类覆盖,提高系统的安全性。
  2. 避免重复加载:确保类只被加载一次,提高性能和内存利用率。

打破双亲委派机制的三种方法

一、自定义类加载器

自定义一个类加载,重写loadClass()方法,清除双亲委派机制的代码,实例:

@Override
    public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        // 检查类是否已经加载
        Class<?> c = findLoadedClass(name);

        // 如果类未被加载,尝试加载类
        if (c == null) {
            try {
                // 自定义类加载逻辑
                c = findClass(name);
            } catch (ClassNotFoundException e) {
                // 如果找不到类,再尝试使用父类加载器加载
                if (getParent() != null) {
                    c = getParent().loadClass(name);
                } else {
                    throw new ClassNotFoundException(name);
                }
            }
        }

        // 如果需要链接类
        if (resolve) {
            resolveClass(c);
        }

        return c;
    }

二、利用线程上下文类加载器

调用线程上下文类加载器(通常是应用程序类加载器)来打破双亲委派机制,思路是当一个类的类加载器是启动类或扩展类加载器时,是无法通过双亲委派机制去委派到应用程序类加载器的,假如需要加载的类又只有应用程序类加载器中有,那么此时就可以通过线程上下文类加载器去加载,因为线程上下文类加载器通常保存的是应用程序类加载器。

// 获取当前线程的上下文类加载器
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
利用线程上下文类加载器到底有没有打破双亲委派机制?

在笔者看来是没有直接打破双亲委派机制的,因为线程上下文类加载器依然是按照双亲委派机制去加载类,线程上下文类加载器只是提供了一种更灵活的方式去加载类。

三、OSGI框架的类加载器

OSGI框架自己实现了一套类加载机制打破了双亲委派机制,在OSGI中允许同级类互相委派,并且OSGI还使用类加载器实现了项目的热部署。

总结

类加载器:加载 Java 类字节码到 JVM 的组件,负责类的查找、加载和连接。

类加载器的分类

  1. 启动类加载器(Bootstrap ClassLoader):加载核心 Java 类库。
  2. 扩展类加载器(Extension ClassLoader):加载扩展类库。
  3. 应用类加载器(Application ClassLoader):加载应用程序类。

双亲委派机制:类加载请求先递交给父类加载器处理,避免重复加载和确保核心类安全。

打破双亲委派机制的三种方法

  1. 自定义类加载器:自定义逻辑加载类,绕过父类加载。
  2. 线程上下文类加载器:通过修改线程的上下文类加载器,动态选择类加载器。
  3. 使用 OSGi 框架:OSGi 自带的类加载机制支持模块化和隔离,突破双亲委派。

标签:委派,自定义,应用程序,线程,双亲,加载
From: https://blog.csdn.net/m0_71386740/article/details/140870207

相关文章

  • 在新页面却加载旧页面的接口
    问题:使用甘特图gantt时,做了一个功能,双击甘特图数据能进行搜索详细情况//3.7双击显示明细gantt.config.details_on_dblclick=true;//监视if(this.eventId){gantt.detachEvent(this.eventId);//先移除之前的事件绑定}thi......
  • 双亲委派机制一
    类加载器JDK8类加载器是Java虚拟机提供给应用程序去实现获取类和接口字节码数据的技术类加载器只参与加载过程中的字节码获取并加载到内存这一部分类加载器的分类扩展类加载器ExtClassLoader应用程序类加载器AppClassLoader启动类加载器BootstrapClassLoader(虚拟机底层......
  • 如何在python中通过requests和opencv加载uint16 png文件
    我正在尝试从URL自动加载图像,然后将其加载到numpy矩阵。为此,我需要使用requests和opencv库。对于像uint8这样编码的标准图像,它以正确的方式工作,并且由于值溢出而损坏了uint16图像。这是我现在正在使用的一个简单的最小代码:importrequestsimportcv2importnumpy......
  • 运行期加载时共享库路径搜索优先级实验
    目录前言实验环境目录说明单独测试不配置路径默认路径ld.so.cacheRUNPATHLD_LIBRARY_PATHRPATH优先级测试附录库文件源码主程序源码makefile脚本run_nonerun_defaultrun_ld_so_cacherun_runpathrun_ld_library_pathrun_rpathrun_cmp_all前言《共享库链接和加载时的路径搜索优先......
  • Vue Hook 封装图片懒加载通用业务
     一、什么是图片懒加载图片懒加载(LazyLoading)是一种在用户需要的时候(通常是滚动到可视区域)才加载图片的技术。通过这种方式,可以减少页面的初始加载时间,减少带宽消耗,提高用户体验。二、Vue中使用IntersectionObserver实现图片懒加载IntersectionObserver是一个现代浏览器......
  • 处理卸载过滤和改写文件加载过滤的问题通常需要在编程或系统管理层面进行以下措施:
    处理卸载过滤和改写文件加载过滤的问题通常需要在编程或系统管理层面进行以下措施:1. 系统检测和监控确保系统中有足够的检测和监控措施,可以发现是否有未经授权的文件加载过滤器被安装或启用。使用安全工具和防病毒软件:常规扫描可以帮助发现异常的系统行为和不寻常的文件加载......
  • WebApi连接数据库报错:尝试加载Oracle客户端时引发BadImageFormatException
    出现的问题  今天在公司用C#搭建一个WebApi服务,接受请求并连接数据库进行查询,但连接数据库时报错:尝试加载Oracle客户端时引发BadImageFormatException。如果安装32位客户端组件的情况下以64位模式运行,将出现此问题。问题点  我之后了解点,确定了OracleClient客户端确实安装......
  • Unity中调试Scroll View,一个Scroll View可以加载不同的图片
    1.所有的图片宽度要相同(最好)2.锚点设置usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;usingUnityEngine.UI;publicclassScrollImageScale:MonoBehaviour{publicImageimage;publicGameObjectcontent;privatef......
  • Tensorboard step和图片加载不完全处理办法
    importtorchvisionfromtorch.utils.dataimportDataLoaderfromtorch.utils.tensorboardimportSummaryWriter#加载CIFAR10测试数据集#参数说明:#"./dataset":数据集保存路径#train=False:加载测试集而非训练集#transform:将图像转换为PyTorch张量test_da......
  • 记一次解决SpringBoot项目由于依赖加载顺序问题导致启动报NoSuchMethodError的问题
    只发博客园,盗版必究先说背景平时我们的SpringBoot项目都是打成ExecutableJar启动应用,最近接了个技术需求,需要打成War包,将多个项目放在同一个Tomcat中运行。原本Jar包启动一切正常,但是打成WAR放Tomcat启动后报错了,异常栈如下:Causedby:org.springframework.beans.factory.......