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

原文地址:https://www.cnblogs.com/manmanchanglu/p/12437383.html