Java虚拟机(JVM)-类加载ClassLoader(三)

本文深入探讨Java虚拟机(JVM)的类加载机制,包括启动类加载器、平台类加载器及应用程序类加载器的工作原理。解析双亲委派模型如何确保类的唯一性,并讨论其在JDK9后的变化,以及自定义类加载器的应用场景。
摘要由CSDN通过智能技术生成

Java虚拟机(JVM)-类加载ClassLoader(三)

类加载机制

在这里插入图片描述

  • JVM自带的加载器包括如下几种

    • 启动类加载器(BootStrapClassLoader)
      • 用于加载启动的基础模块类,比如
    • 平台类加载器(PlatformClassLoader)备注:JDK9之前是扩展类加载器(ExtensionClassLoader)】
    • 应用程序类加载器(AppClassLoader)
      • 用于加载应用级别的基础模块类和程序员开发的Class
  • 用户自定义类加载器

    • 自定义类加载器是在所有系统类加载器执行之后才可以执行
  • 下图是父子关系而非继承关系【重点,此处容易产生误解】
    在这里插入图片描述

package com.unicorn.classloader;

/**
 * @desc: TODO
 * @author: quan
 * @date: 2020-07-18 21:24
 */
public class ClassLoaderStudy {

    public static void main(String[] args) throws ClassNotFoundException {

        //BootStrapClassLoader 由于BootStrapClassLoader是虚拟机的基础模块,不允许业务上做任何操作,因此getClassLoader() 是NULL
        String str = "Hello class loader study by BootStrapClassLoader";
        System.out.println("str class Loader =" + str.getClass().getClassLoader());
        Class driver = Class.forName("java.sql.Driver");
        System.out.println("driver class Loader =" + driver.getClassLoader());

        //ExtClassLoader

        //AppClassLoader APP应用程序ClassLoader
        System.out.println("ClassLoaderStudy class Loader =" + ClassLoaderStudy.class.getClassLoader());
        System.out.println("ClassLoaderStudy.parent class Loader =" + ClassLoaderStudy.class.getClassLoader().getParent());
        System.out.println("ClassLoaderStudy.parent.parent class Loader =" + ClassLoaderStudy.class.getClassLoader().getParent().getParent());
    }
}

双亲委派模型

  • 双亲委派模型工作过程:(jdk9以下,jdk9开始引入了模块化的概念,此处会有细微的差别)
    • 如果一个类加载器接收到了类加载的请求,它首先不会自己去尝试去加载这个类,而是把这个请求委派给父级加载器去完成
    • 每一个层次的类加载都是如此,因此所有的类加载请求都应该传送到顶层启动类加载器中,只有当父加载器反馈自己无法加载这个请求,子类加载器才会去尝试自己加载。
  • 双亲委派模型核心代码java.lang.ClassLoader#loadClass(java.lang.String, boolean)
/**
     * Loads the class with the specified <a href="#name">binary name</a>.  The
     * default implementation of this method searches for classes in the
     * following order:
     *
     * <ol>
     *
     *   <li><p> Invoke {@link #findLoadedClass(String)} to check if the class
     *   has already been loaded.  </p></li>
     *
     *   <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method
     *   on the parent class loader.  If the parent is <tt>null</tt> the class
     *   loader built-in to the virtual machine is used, instead.  </p></li>
     *
     *   <li><p> Invoke the {@link #findClass(String)} method to find the
     *   class.  </p></li>
     *
     * </ol>
     *
     * <p> If the class was found using the above steps, and the
     * <tt>resolve</tt> flag is true, this method will then invoke the {@link
     * #resolveClass(Class)} method on the resulting <tt>Class</tt> object.
     *
     * <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link
     * #findClass(String)}, rather than this method.  </p>
     *
     * <p> Unless overridden, this method synchronizes on the result of
     * {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method
     * during the entire class loading process.
     *
     * @param  name
     *         The <a href="#name">binary name</a> of the class
     *
     * @param  resolve
     *         If <tt>true</tt> then resolve the class
     *
     * @return  The resulting <tt>Class</tt> object
     *
     * @throws  ClassNotFoundException
     *          If the class could not be found
     */
    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 {
                	//TODO 看这里,先通过父级ClassLoader加载器进行查找
                    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;
        }
    }

破坏双亲委派模型

  • 此处仅作了解即可
    在这里插入图片描述
  • 常见的是jdbc驱动加载的问题
    • java.sql.DriverManager#getConnection(java.lang.String, java.util.Properties, java.lang.Class<?>)
      在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值