双亲委派模型初探

前言~

最近个人在研究SPI机制的底层,SPI实现中一大重点就是打破了双亲委派模型.既然要学会SPI,那就必须了解什么是双亲委派模型,SPI为什么要打破双亲委派模型?

而这一切的前提都是要了解双亲委派模型.故这就是本博客书写的原因~~


以下是正文

要介绍双亲委派模型,自然是要先介绍其概念~~

双亲委派模型(Parent-Delegation Model)是Java类加载机制中的一种模型,它用于描述Java虚拟机在加载类时的行为.

在Java虚拟机中,每个类都由一个类加载器来加载,让类加载器之间形成了一种层次分明的结构~根加载器位于最顶层,而Ext,App等类加载则依次往下,负责加载各自的类.Java虚拟机会按照一定的顺序查询每个类加载器,查看是否能找到该类,这种查询顺序我们一般将其称为双亲委派模型.

双亲委派机制的工作原理如上图,当一个类加载器需要加载一个类时,它会检查该级虚拟机内有无加载此类,若无,则会把该类委托给它的父加载器,父加载器重复这个流程,直到委派给最顶端的根加载器.如若根加载器无法加载,则由下一级的类加载器加载,依次循环至最下层的类加载器为止.

对于这一部分,我做了一部分的源码探究,首先,在类加载器加载类(loadClass)时,代码会运行至java.lang.ClassLoader(抽象类)中如图所示的位置:

继续向下追踪,可以看到这段核心代码:

 加锁什么的我就不解释了,第一句重点代码:

// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);

其上的注释也很好解释了它的作用:先查找该类是否已经被加载,能在虚拟机中找到.并将查找的结果存至c.请注意!这一段起的作用更类似于缓存的效果,并非直接用该类加载器直接加载!

之后的重点便是这一段:

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
        }

首先判断c是否为空(若已经被虚拟机加载c便会非空),(中间的时间记录啥的不算重点),然后判断其是否拥有父加载器.若有,则递归至父加载器重新执行该段函数.直至根加载下一级为止,此时,parent为空,便执行else中语句,在根加载器中尝试加载该类.至于catch,emmm注释上也说得很清楚,如果没有从非空的父类加载器中找到类,则抛出ClassNotFoundException.不过catch到这个异常后并没有什么处理罢了~

之后看看这一段代码:

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();
}

在确认c为空(未在虚拟机中加载且父加载器类未能加载该类)后,便会执行findClass方法,尝试加载该类,之后哪些时间统计啥的不做描述,自行查看注释即可~

之后该段递归结束,将c返回子类加载器,就在这:

若是父加载器加载成功自不必多说, 若是父加载器没有加载到~~那就再来一遍吧!

 至此,我基本对双亲委派机制的源码有了部分初略的理解~(//TODO:研究findClass具体实现)

而双亲委派的优点也很明显:保证类的唯一性.

仔细设想:当一个类被某个类加载器加载时,它能确保从根加载器类开始,且加载完毕会"缓存"至虚拟机中,在下次加载时可直接取用,自然保证了其唯一性,让系统更加安全.

那么这种方式有没有缺点?有!其优点某种意义上正是其缺点,再次设想一下:就比如我新增一个tomcat容器,它能和我在java本身共用类加载器吗?这样的话如何保证相互间的独立性?毕竟不同的应用程序可能会依赖一个第三方类库的不同版本.此时再用双亲委派模型自然不妥.这时,我们便需要打破双亲委派模型,保证互相隔离.

至此,初探双亲委派模型才算结束,双亲委派模型解释,为什么要打破双亲委派模型的目的正式达成~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值