双亲委派模型

最近在和同学聊天的时候,听他们说去面试的时候双亲委派是一个高频知识点,而且基本都是被虐的体无完肤,我也思考了我自己在平时的工作中碰到的和了解过的知识点,这个平时确实是用的不多(大佬请绕过,哈哈),之前看到过一些博客文章也有写,不过看过之后就忘记了。废话不多说下面开始正文:

文章主要从五个部分说起:双亲委派是什么?怎么实现的这部分功能?为什么要有双亲委派?为什么要破坏双亲委派?如何破坏双亲委派?

一、双亲委派是什么?

双亲委派说的是:当一个类加载器在收到加载类的请求时,自己不首先去加载,而是去找他的父加载器去加载,一直向上找,如果父加载器都无法加载,他才自己尝试加载。

Java虚拟机中一般都有的三种加载器:Bootstrap ClassLoader,Extension ClassLoader和Application ClassLoader。

Bootstrap ClassLoader 加载<JAVA_HOME>\lib中的,或者被-Xbootclasspath参数所指定的路径中的,并且能够被虚拟机识别的类(通过名字识别,如果名字对应不上,即使放进去了也不会被加载);

Extension ClassLoader主要是加载<JAVA_HOME>中,或者java.ext.dirs指定路径中的所有类;

Application ClassLoader主要是加载用户类路径下的类,如果没有指定,他就是作为应用程序的默认加载器。

除了上述三种加载器,用户可以自定义类加载器,去实现类的加载。他们的关系如下图所示:
在这里插入图片描述

二、为什么要用双亲委派?

Java中有很多的基础类,比如Object类,他是所有对象的父类,而且他的加载最终都是交给了Bootstrap ClassLoader去加载,这样在任何情况下,都是相同的一个类,如果不是这样的话,可能就会有很多这样的类,这样就会很麻烦。而且这样做使得java类天生就带着层级,结构非常的清晰。

三、怎么实现的这部分功能?

类加载主要是通过java.lang.ClassLoader来实现,代码非常简单,如果类已经被加载就立马返回,如果没有被加载并且父加载器不为空,就调用父加载器去加载,如果没有被加载切父加载器为空,就直接用BootstrapClassLoader去加载,如果加载不到就抛出ClassNotFound异常,然后调用自己的类加载器去加载,如下所示:

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
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

四、为什么要破坏双亲委派?

跟中国的文化一样,所有的词都有一个正反,你要执着,你不要钻牛角尖等等还有很多有意思的词语。双亲委派也一样,为什么要破坏双亲委派呢?举一个最常见但是容易被咱们忽视的一个点,tomcat里边的多个应用,一个应用用的是commons-lang-2.4.jar,另一个应用用的是commons-lang-3.4.jar,如果还是按照双亲委派模型去加载,是无论如何都加载不了包路径、类名一样的两个类的。还有很多其他方面的应用,比如说JDBC里边的SPI创建数据库连接的时候,也破坏了双亲委派,有兴趣的话可以去研究一下。

五、如何破坏双亲委派?

我们知道了双亲委派是怎么实现的,那么“破坏”起来就方便了很多,就是重写loadClass就可以了。但是如果我们要自定义一个类加载器,但是不破坏双亲委派模型,那么我们就重写一下findClass方法就可以了。

强烈推荐下图所示公众号:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序猿每日分享

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

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

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

打赏作者

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

抵扣说明:

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

余额充值