通俗易懂的雙親委託

雙親委託模型

一、什麼是雙親委託

​ 雙親委派模型,就是如果一個類加載器收到了類加載請求,它並不會自己先去加載,而是把這個請求委託給父類的加載器去執行,如果父類加載器還存在其父類加載器,則進一步向上委託,依次遞歸,請求最終將到達頂層的啓動類加載器,如果父類加載器可以完成類加載任務,就成功返回,倘若父類加載器無法完成此加載任務,子加載器纔會嘗試自己去加載,這就是雙親委派模型

二、源碼分析

Class aClass = ClassLoader.getSystemClassLoader().loadClass("MainActivity");

​ 首先,我們先看下,像上述一個類(MainActivity)是如何通過反射被加載出來的

//public abstract class ClassLoader
protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
        // First, check if the class has already been loaded
        //1.首先看該類是否應加載過,有則直接返回
        Class<?> c = findLoadedClass(name);
        if (c == null) {
        //2.沒有加載過,則調用parent.loadClass方法去父類中去加載
            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
            }
			//3.當父類中不存在時,則自己通過findClass方法去加載
            if (c == null) {
                // If still not found, then invoke findClass in order
                // to find the class.
                c = findClass(name);
            }
        }
        //4.返回該對象
        return c;
}

如圖中的代碼,整體的邏輯爲,當我們根據類名加載一個類時,

1.首先看該類是否應加載過,有則直接返回

2.沒有加載過,則調用parent.loadClass方法去父類中去加載

3.當父類中不存在時,則自己通過findClass方法去加載

4.返回該對象

三、理解

​ 上述的代碼,就是一個標準的雙親委託模型,就完了,就怎麼多,怎麼樣,是不是感覺內容很少,和腦海中對他的幻想存在很多差別,現在,咱們就從上面的代碼來看看這個模型的好處在哪裏,優勢是什麼

​ 舉個例子,假設一個類加載器的結構是這樣的AClassLoader extends BClassLoader,BClassLoader extends ClassLoader。當AClassLoader 中有一個Test.class類,BClassLoader中也有一個Test.Class類時,我們調用AClassLoader .loadClass(“Test”);時,加載的是哪個類呢?

​ 根據上面的源碼邏輯,當我們調用aClassLoader.loadClass方法時,先看該類是否加載過,在首次時沒有加載過,則調用父bClassLoader的loadClass方法,b也因首次請求未加載過該類,則請求基類ClassLoader,ClassLoader中也沒有,由於是根類,則通過該類的findclass方法去找,未找到,則通知bClassLoader未空的結果,b則根據空結果,去自身的findclass方法中去查找,找到了,則返回該B 中的Test.class。

四、優勢

​ **1.這種層級關係可以避免重複加載:**Java類隨着它的類加載器一起具備了一種帶有優先級的層次關係,通過這種層級關可以避免類的重複加載,當父親已經加載了該類時,就沒有必要子ClassLoader再加載一次。

​ **2.在安全的角度,可以在一定程度上方式源碼被替換:**假設通過網絡傳遞一個名爲java.lang.Integer的類,通過雙親委託模式傳遞到啓動類加載器,而啓動類加載器在覈心Java API發現這個名字的類,發現該類已被加載,並不會重新加載網絡傳遞的過來的java.lang.Integer,而直接返回已加載過的Integer.class,這樣便可以防止核心API庫被隨意篡改。

五.自定義類加載器

​ 一個簡單的自定義類加載器的方式如下

public class test extends ClassLoader{

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        //如果你想破壞雙親委託的模型,你可以重寫這個方法.畢竟用戶的需求是多種多樣的,你開發出一個甜品店,保不齊有人非要過來買條狗。。
        return super.loadClass(name);
    }


    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        //如果你想保持雙親委託的模型,請重寫這個方法
        return super.findClass(name);
    }
}

​ 原因則可以參照源碼分析時的過程來理解(當父類中不存在時,則自己通過findClass方法去加載),並且,原生的註釋也對這兩個方法的用途解釋的很明白了

/**
 * Loads the class with the specified <a href="#name">binary name</a>.
 * This method searches for classes in the same manner as the {@link
 * #loadClass(String, boolean)} method.  It is invoked by the Java virtual
 * machine to resolve class references.  Invoking this method is equivalent
 * to invoking {@link #loadClass(String, boolean) <tt>loadClass(name,
 * false)</tt>}.
 *
 * @param  name
 *         The <a href="#name">binary name</a> of the class
 *
 * @return  The resulting <tt>Class</tt> object
 *
 * @throws  ClassNotFoundException
 *          If the class was not found
 */
public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}

 /**
     * Finds the class with the specified <a href="#name">binary name</a>.
     * This method should be overridden by class loader implementations that
     * follow the delegation model for loading classes, and will be invoked by
     * the {@link #loadClass <tt>loadClass</tt>} method after checking the
     * parent class loader for the requested class.  The default implementation
     * throws a <tt>ClassNotFoundException</tt>.
     *
     * @param  name
     *         The <a href="#name">binary name</a> of the class
     *
     * @return  The resulting <tt>Class</tt> object
     *
     * @throws  ClassNotFoundException
     *          If the class could not be found
     *
     * @since  1.2
     */
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章