• Java类加载器(双亲委派模型)(综述)


    原文链接:https://blog.csdn.net/qq_32679835/article/details/92848424

    类加载器
    一、预定义类型类加载器
    1、启动(Bootstrap)类加载器,负责将 <Java_Runtime_Home>/lib 下面的类库加载到内存中。
    2、扩展(Extension)类加载器ExtClassLoader:负责将 < Java_Runtime_Home >/lib/ext 或者由系统变量 java.ext.dir 指定位置中的类库加载到内存中
    3、系统(System)类加载器AppClassLoader:负责将系统类路径(CLASSPATH)中指定的类库加载到内存中。
    4、线程上下文类加载器ThreadContextClassLoader(TCCL):用于解决双亲委托模型的缺陷,可以实现核心库接口加载系统类(这一条先忽略)
    二、类加载器结构

    1、jvm加载的顺序:BoopStrap ClassLoder–>ExtClassLoader–>AppClassLoder
    2、类加载器之间的关系:AppClassLoader的父加载器为ExtClassLoader,ExtClassLoader的父加载器为BoopStrap ClassLoader,BoopStrap ClassLoader为顶级加载器。
    考虑一下类加载器的结构为什么会选择首先通过父类加载器去加载,只有父类无法加载了才会使用子类加载器去加载?(类加载器代理模式)
    首先需要去明确一点,如果是相同的Java类,当使用不同的类加载器加载,并通过加载器获得的java.lang.Class实例化的对象,这两个实例化对象实不相等的。有了这个前提之后,在java中会具有一些核心类,如果去使用自身类加载器,实例化后就会造成这些类之间不兼容。因此会选择代理模式,对于 Java 核心库的类的加载工作由引导类加载器来统一完成,保证了 Java 应用所使用的都是同一个版本的 Java 核心库的类,是互相兼容的。

    双亲委派模型

    一、双亲委派模型流程

     根据类加载器流程图,当需要查找一个class对象时候,由于类加载机制只要加载过该类,就不需要去重新加载,只需要查找缓存
    1、缓存路:查找自身加载器是否有缓存,没有则委托父类AppClassLoader加载器---->查找AppClassLoader加载器是否有缓存,没有则委托父类ExtClassLoader---->查找ExtClassLoader加载器是否有缓存,没有则委托BoopStrap加载器–>查找BoopStrap加载器是否有缓存,没有则开始加载(在任何一个加载器中该类已经加载,则直接返回)
    2、加载路:BoopStrap在核心库中加载,如果未加载成果---->ExtClassLoader在lib/ext中加载,如果未加载成果----->AppClassLoader在当前classpath中加载,如果未加载成果---->自定义加载器加载,如果未加载成果---->抛出异常ClassNotFoundException

     二、双亲委派模型源码

    protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
        {
            synchronized (getClassLoadingLock(name)) {
                // 首先,检查是否已经加载过
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();
                    try {
                        if (parent != null) {
                            //父加载器不为空,调用父加载器的loadClass
                            c = parent.loadClass(name, false);
                        } else {
                            //父加载器为空则,调用Bootstrap Classloader
                            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();
                        //父加载器没有找到,则调用findclass
                        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()
                    resolveClass(c);
                }
                return c;
            }
        }
    

      

    自定义类加载器

    一、类加载器继承关系

     四、双亲委托模型的破坏
    1、第一次破坏
    第一次模型的破坏就是指在jdk1.2之前,因为此时还没有引入双亲委托模型,用户在自定义类加载器的时候需要去重写loadclass(),因为虚拟在进行类加载的时候会调用加载器的私有方法loadClassInternal(),而这个方法的唯一逻辑就是去调用自己的loadClass()。jdk1.2之后就不提倡用户去重写loadclass(),类加载逻辑写到findclass()中,保证新写出的类符合双亲委托模型。
    2、第二次破坏
    第二次的破坏是由于双清委托模型自身的缺陷导致,Java 提供了很多服务提供者接口(Service Provider Interface,SPI),允许第三方为这些接口提供实现。常见的 SPI 有 JDBC、JCE、JNDI、JAXP 和 JBI 等。
    这些 SPI 的接口由 Java 核心库来提供,而这些 SPI 的实现代码则是作为 Java 应用所依赖的 jar 包被包含进类路径(CLASSPATH)里。SPI接口中的代码经常需要加载具体的实现类。那么问题来了,SPI的接口是Java核心库的一部分,是由启动类加载器(Bootstrap Classloader)来加载的;SPI的实现类是由系统类加载器(System ClassLoader)来加载的。引导类加载器是无法找到 SPI 的实现类的,因为依照双亲委派模型,BootstrapClassloader无法委派AppClassLoader来加载类。

     

     引用
    【1】双亲委派模型流程图:https://www.cnblogs.com/gdpuzxs/p/7044963.html
    【2】ExtClassLoader和AppClassLoader继承关系图:http://www.360doc.com/content/16/0614/10/7510008_567634519.shtml
    【3】ExtClassLoader和AppClassLoader实现差异性:
    loaderClass与findClass区别:https://blog.csdn.net/caomiao2006/article/details/47735245
    【4】比较好:http://www.blogjava.net/zhuxing/archive/2008/08/08/220841.html
    【5】第二次破坏,线程上下文类加载器:https://blog.csdn.net/yangcheng33/article/details/52631940

  • 相关阅读:
    BZOJ 1433 && Luogu P2055 [ZJOI2009]假期的宿舍 匈牙利算法
    BZOJ 1123 && Luogu P3469 [POI2008]BLO-Blockade 割点+乘法原理
    POJ3694 Network 边双缩点+LCA+并查集
    luogu P5142 区间方差 十分优美的线段树
    luogu P2709 小B的询问 最简单的莫队
    luogu P2731 骑马修栅栏 Riding the Fences
    TYVJ P2032 「Poetize9」升降梯上 spfa最短路
    51nod 1515 明辨是非 并查集+set维护相等与不等关系
    BZOJ 1260: [CQOI2007]涂色paint 区间DP
    luogu P4145 上帝造题的七分钟2 / 花神游历各国 维护区间和&&区间开根号
  • 原文地址:https://www.cnblogs.com/manmanchanglu/p/12437383.html
Copyright © 2020-2023  润新知