首页 > 其他分享 >双亲委派机制和SPI的理解

双亲委派机制和SPI的理解

时间:2024-07-07 21:52:22浏览次数:14  
标签:委派 cn class SPI 双亲 Class 加载

双亲委派机制和SPI的理解

双亲委派机制基本原理

双亲委派机制简单的来说是JVM类加载过程的一个非强约束模型。子类加载器加载对应的Class,不会直接加载,首先会交由其父类加载器加载,若父类加载器无法加载,则由自己加载。

Java一共有三层类加载器,级别从上往下依次是:

  • BootStrap Class Loader:该类加载器由C++实现,在java语言中无法感知,所以在获取类加载器为null,主要用于加载<JAVA_HOME>\lib 目录下的类。当然也可自己通过JVM参数指定。

  • ExtClassLoader:扩展类加载器,主要用于加载<JAVA_HOME>\lib\ext 目录下的类。

  • AppClassLoader:系统类加载器,用大白话来讲,就是加载我们自己定义的类的类加载器还有引入的一些第三方jar包。

    具体的示例代码如下:

    System.out.println(HashMap.class.getClassLoader()); // null
    System.out.println(JarFileSystemProvider.class.getClassLoader()); //sun.misc.Launcher$ExtClassLoader@355da254
    System.out.println(Main.class.getClassLoader()); // sun.misc.Launcher$AppClassLoader@18b4aac2
    

双亲委派机制的具体实现可以参考ClassLoader#loderClass方法,具体代码如下:

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                     // 先从父加载器加载
                     if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    // 父加载器加载失败,自己加载
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

不难发现,在Jdk源码中,类加载器自身加载类的方法其实findClass,因此官方推荐自定义类加载器的时候,建议重载findClass,而不是loadClass方法,因为lodaClass方法重载后,若开发者没有按照规范开发,便会打破双亲委派机制。

双亲委派机制存在意义

  • 有序性】首先,双亲委派机制能够有效的避免一个类被重复加载,一个类只会被加载一次。若一个类被父类加载器加载,对于子类加载器其实是无感的,若子类加载器直接加载对应的class,会导致一个类被重复加载。

  • 安全性】同样也是处于安全性考虑,如果JDK和核心类库,被其他类加载器加载,Java中最基础的行为也就无法保证。在双亲委派的场景下,能够确保被BootStrap类加载器加载,就不会出现上述问题。

双亲委派的破坏

  • 通过自定义类加载器,重写loadClass来破坏双委派。

  • JNDI (Java Naming and Directory Interface,Java命名和目录接口) 需要服务者提供接口实现代码(SPI)。这里一个典型的应用就是JDBC的Driver驱动实现,各个数据库厂商可以针对JavaEE中的规范自行实现。这里主注意的是只有Java类库中的SPI才会对双亲委派进行破坏,自定义接口和第三方Jar包并不会对双亲委派机制进行破坏。以Driver的SPI为例,参考ServiceLodar#nextService

    破坏双亲委派的代码就是Class.forName(cn, false, loader) 这一行。

    传入的是一个loader,默认是系统类加载器。

     private S nextService() {
                if (!hasNextService())
                    throw new NoSuchElementException();
                String cn = nextName;
                nextName = null;
                Class<?> c = null;
                try {
                    // 双亲委派被破坏
                    c = Class.forName(cn, false, loader);
                } catch (ClassNotFoundException x) {
                    fail(service,
                         "Provider " + cn + " not found");
                }
                if (!service.isAssignableFrom(c)) {
                    fail(service,
                         "Provider " + cn  + " not a subtype");
                }
                try {
                    S p = service.cast(c.newInstance());
                    providers.put(cn, p);
                    return p;
                } catch (Throwable x) {
                    fail(service,
                         "Provider " + cn + " could not be instantiated",
                         x);
                }
                throw new Error();          // This cannot happen
     }
    

    如果直接写出Class.forName(cn),那他的加载器就是ServiceLoader的类加载器,而ServiceLoader位于<JAVA_HOME>\lib,它的类加载器是BootStrap类加载器,显然无法加载第三方jar包及其用户自定义代码,需要指定子类加载器,BooStrap类加载器将类加载委托给AppClassLodaer。因此就造成双亲委派被破坏。

  • 不难发现,由于双亲委派机制的存在,一个类至始至终只会被加载一次,因此当程序需要热更新时,双亲委派机制也就随之被破坏。

标签:委派,cn,class,SPI,双亲,Class,加载
From: https://www.cnblogs.com/magicwang0907/p/18288979

相关文章

  • pspice里面的VSTIM波形设置问题
    在网上看了关于vpwl的波形的定义,发现没有得到正确的结果,经过尝试,最终设置成功 ,可能选项有些歧义.这里的v1是sourcetm里面的vstim.有几个条件要正确:1,包含文件库,在profile里面,2.元件属性设置,这个实例名要注意,不是文件名,实例路径是带路径的文件名这样就可以......
  • 【中国算力大会分会,SPIE独立出版!AHPCAI前三届已完成EI检索!】2024算法、高性能计算与人
    2024算法、高性能计算与人工智能国际学术会议(AHPCAI2024)定于2024年8月14-16日在中国郑州举行。会议主要围绕算法、高性能计算与人工智能等研究领域展开讨论。会议旨在为从事算法、高性能计算与人工智能研究的专家学者、工程技术人员、技术研发人员提供一个共享科研成果......
  • 通信协议 | 一文搞懂SPI通信协议
    SPI的英文全称为SerialPeripheralInterface,顾名思义为串行外设接口。SPI是一种同步串行通信接口规范,主要应用于嵌入式系统中的短距离通信。该接口由摩托罗拉在20世纪80年代中期开发,后发展成了行业规范。SPI是一种高速的、全双工的、同步的通信总线,并且至多仅需使用......
  • 【SPIE 独立出版 | 高录用稳检索 | 过往4届均已检索】第五届计算机视觉和数据挖掘国际
    第五届计算机视觉与数据挖掘国际学术会议(ICCVDM2024)将于2024年7月19-21日在中国长春举行。此前,ICCVDM系列会议于2020年在中国西安、2021年在中国长沙(线上)、2022年在中国呼伦贝尔(线上+线下)、2023年在中国长春(线上+线下)皆已成功举办。ICCVDM为世界各地该领域的专家、学者......
  • 脉冲神经网络(Spiking Neural Network,SNN)相关论文最新推荐(一)
    用稀疏代理梯度直接训练时态脉冲神经网络论文链接:www.sciencedirect.comBenchmarkingArtificialNeuralNetworkArchitecturesforHigh-PerformanceSpikingNeuralNetworks论文链接:www.mdpi.comHierarchicalspikingneuralnetworkauditoryfeaturebaseddry-typet......
  • 面试官:如何打破双亲委派机制?
    面试连环call双亲委派机制是什么?如何打破双亲委派机制?JVM都有哪些类加载器?如何构造一个自定义类加载器?Tomcat的类加载机制?Spring的类加载机制Class.forName()和ClassLoader.loadClass()区别?在开始讲述之前简单回顾一下之前的类加载过程类加载过程:加载->连接->初始化。......
  • sping-10
    什么是bean装配   在Java中,bean装配是一种将对象(也称为bean)与其他对象之间建立关联关系的方法。这种装配可以通过手动编写代码来实现,也可以使用依赖注入框架(如Spring)来自动完成。在bean装配中,有三种主要的方式:构造函数注入、setter方法注入和自动装配。构造函数注入......
  • SpingMvc-Day02
    SpringMVC:表述层作用:1.接受前端参数[SpringMVC简化] 2.调用业务逻辑 3.响应前端数据[SpringMVC简化]SpringMVC组件: 1.DispatcherServlet:处理全部请求 2.handlerMapping:缓存handler方法和地址 3.handlerAdapter:适配器、参数和相应简化 4.ViewResovler视图解释器:查找视图页面......
  • STM32L073RZT 调试SPI问题
    现象描述:spi通信一次后,第二次通信spi的SR寄存器异常0xFF31(MODF,CRCERR,RXNE),通信失败。以下为调用流程及相关代码:NFC_ID();NFC_REG_B_TEST(); //SPI读voidSPI_Read_Data(uint8_t*w_data,uint32_tw_size,uint8_t*r_data,uint32_tr_size){SET_SPI......
  • DEV中SpinEdit使用
    属性:      spinEdit1.BorderStyle=DevExpress.XtraEditors.Controls.BorderStyles.Office2003;//设置边框样式      spinEdit1.EnterMoveNextControl=true;//但用户按Enter键时是否将焦点移动到下一个控件      spinEdit1.ForeColor=......