(3)JVM 类加载之双亲委派机制

前言

上一节(2)JVM 类加载之类加载器初始化记录了JVM自带的3中类加载器,也分析了类加载器初始化的流程。那么问题来了:

  1. 这么几种类加载器之间的关系是什么?
  2. 有这么几种类加载器,怎么确定一个类由哪个类加载器加载?
  3. 为什么要分这么几种类加载器呢?一个类加载器不也能加载吗?
  4. 能够打破双亲委派机制吗?

本文涉及到的源码都在JDK的jre\lib\rt.jar包中。

一、双亲委派机制

1、各个类加载器之间的关系

双亲委派机制用在一个类被加载之前,因为需要判断由哪个类加载器去加载这个类。双亲委派机制在Java运行一个类的流程中的位置如图:
双亲委派
从图中可以看出,引导类加载器是拓展类加载器的父加载器,拓展类加载器是应用程序类加载器的父加载器,应用程序类加载器是自定义类加载器的父加载器。在加载一个类之前,若没有自定义类加载器,则默认是从应用程序类加载器开始加载,逐级委托父级类加载器,最终委托到引导类加载器。若引导类加载器不能加载需要加载的类,则委派拓展类加载器进行加载;若拓展类加载器仍不能进行加载,则委派应用程序类加载器来完成加载。若自定义了类加载器,并使用自定义类加载器对某个类进行加载,则从自定义类加载器开始逐级委托,然后逐级委派。

为什么这几种类加载器是这样的关系呢?因为源码是这样设计的。

在下面分析之前,先放上一个类图:
类图
这是在IDEA中点击ExtClassLoader然后按组合键Ctrl + alt + U看见的类图,其实这个类图没有画完,我在visio中画了一下:
在这里插入图片描述
可以发现,拓展类加载器虽然是应用程序类加载器的父级加载器,但应用程序类加载器并不是继承于拓展类加载器,只不过在应用程序类加载器的类中有个parent属性,这个属性是从ClassLoader继承过来的,里面存的值就是拓展类加载器对象的引用,所以看起来他们像是父子的关系。其它的加载器情况与上面的类似,自定义类加载器parent应用程序类加载器拓展类加载器parent是null,因为其父类加载器引导类加载器是用C++实现的,在Java里获取不到。

我在(2)JVM 类加载之类加载器初始化中记录过,拓展类加载器应用程序类加载器是在sun.misc.Launcher.getLauncher()这里创建的,那么我们具体再跟进一下,先进入sun.misc.Launcher的构造器:

public Launcher() {
   
    Launcher.ExtClassLoader var1;
    try {
   
        var1 = Launcher.ExtClassLoader.getExtClassLoader();
    } catch (IOException var10) {
   
        throw new InternalError("Could not create extension class loader", var10);
    }

    try {
   
        this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
    } catch (IOException var9) {
   
        throw new InternalError("Could not create application class loader", var9);
    }
    ...
}

(2)JVM 类加载之类加载器初始化中分析得到:

  1. var1是创建的拓展类加载器;
  2. this.loader是创建的应用程序类加载器。

继续跟进getExtClassLoader()

public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
   
    final File[] var0 = getExtDirs();

    try {
   
        return (Launcher.ExtClassLoader)AccessController.doPrivileged(new PrivilegedExceptionAction<Launcher.ExtClassLoader>() {
   
            public Launcher.ExtClassLoader run() throws IOException {
   
                int var1 = var0.length;

                for(int var2 = 0; var2 < var1; ++var2) {
   
                    MetaIndex.registerDirectory(var0[var2]);
                }

                return new Launcher.ExtClassLoader(var0);
            }
        });
    } catch (PrivilegedActionException var2) {
   
        throw (IOException)var2.getException();
    }
}

看到返回值是:

return new Launcher.ExtClassLoader(var0);

那么继续跟进ExtClassLoader(var0)

public ExtClassLoader(File[] var1) throws IOException {
   
    super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);
    SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this);
}

发现进入到了拓展类加载器的一个有参构造器,里面有一行调用其父类的构造器的代码:

super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);

发现传进了一个**(ClassLoader)null**,这其实是其父类加载器,继续跟进super

在这里插入图片描述
继续跟进superparent是上回传进来的null

在这里插入图片描述
再次跟进,parent依然是null

在这里插入图片描述
跟进thisparentnull

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starslightshine

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值