解析双亲委派机制源码

剖析ClassLoader源码,理解双亲委派机制


双亲委派机制是Java的类加载器在处理加载类的任务时的一种分配机制,可以防止类被重复加载或者出现手写类代替系统类的风险,上篇已经全面介绍了双亲委派机制,本篇我们从ClassLoader抽象类的源码上来一探究竟

上篇说到了类加载器会在加载类时先自底向上查找是否被加载过,再由顶向下进行加载,那么他究竟是如何实现的呢,我们可以查看ClassLoader抽象类的源码
ClassLoader 是 Java 类加载机制的核心部分,用于动态加载 Java 类到 JVM 中

首先找到源码

打开IDEA进入任意一个项目,双击SHIFT键即可查找,输入ClassLoader,选择"类"找到java.lang下的ClassLoader抽象类
在这里插入图片描述
其中的含有四个核心方法:
loadClass、findClass、defineClass、resolveClass,他们涉及了类加载的全部过程,进入ClassLoader抽象类按CTRL+F查找四个类名逐一查看:

  • loadClass():类加载的入口,该方法会根据 “双亲委派模型” 首先请求父类加载器加载类。如果父类加载器无法找到目标类,当前 ClassLoader 才会调用 findClass 方法来尝试加载该类。
  • findClass():在 loadClass 的加载逻辑中,如果父类加载器未能找到类,则当前类加载器通过调用 findClass 来查找类的字节码。通常用于自定义类加载器时,负责从自定义源(如文件、网络等)加载类的字节码。
  • defineClass():这个方法用于将二进制字节数组转换为 Class 对象。通常在 findClass 中被调用,用于将从外部源获取的字节码定义为 JVM 中的类。
  • resolveClass():执行类生命周期中的连接阶段

当有类加载任务时,这四个方法的执行顺序和调用关系大致为:

loadClass
父加载器加载成功?
返回已加载类
findClass
加载类字节码
defineClass
resolve?
resolveClass
返回加载类

查看源码

由于我们要探讨的是双亲委派机制的原理,所以我们本篇只解析一下loadClass方法的源码:
他的默认实现是调用重载方法传入参数resolve = false,即不需要调用resolveClass方法,也就是上图的最后一个环节

//默认实现
public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }
//重载方法
    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
                    PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

所以我们重点查看重载方法loadClass(String name, boolean resolve),我们逐步分析这个代码的执行逻辑:

1. 获取类加载锁
synchronized (getClassLoadingLock(name)) 

在加载类时,getClassLoadingLock(name) 会返回与类名关联的锁对象,以确保在多线程环境中同一个类不会被多次加载

2. 检查类是否已经加载
Class<?> c = findLoadedClass(name);
if (c == null) {

源码中的注释写道:First, check if the class has already been loaded(检查类是否已经加载),目的是检查类是否已经被当前 ClassLoader 或父类加载器加载。如果类已经被加载,就不会再次加载它

3. 尝试由父类加载器加载类
if (parent != null) {
    c = parent.loadClass(name, false);
} else {
    c = findBootstrapClassOrNull(name);
}

如果类未被加载(c == null),首先会尝试使用父加载器加载类。这是 “双亲委派模型” 的体现,即优先让父类加载器处理类加载
这里如果parent != null并不是说明当前类加载器没有父类加载器,而是说明当前类加载器的父类是启动类加载器,由于启动类加载器Bootstarp是由C++编写的,java代码中无法直接引用,他会调用findBootstrapClassOrNull(name) 来查找核心类库。

4. 由当前类加载器尝试加载
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
                    PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    PerfCounter.getFindClasses().increment();
                }

如果父类加载器也没有加载成功,则由当前类加载器来进行加载,会调用findClass方法根据类的全限定名,获取类的字节码文件,但是该方法一般由子类进行重写,自定义加载路径以及加载方式

5. 解析并返回类
			if (resolve) {
                resolveClass(c);
            }
            return c;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值