JVM學(xué)習(xí)(二)續(xù)1-ClassLoader代碼解讀-雙親委派模型

1. ClassLoader的繼承關(guān)系

ClassLoader是什么鬼?為什么我們要如此大費(fèi)周章的講解這個(gè)?
還記得AppClassLoader、ExtClassLoader么?他們與ClassLoader之間的關(guān)系是什么?


ClassLoader繼承關(guān)系
AppClassLoader+ExtClassLoader

URLClassLoader

SecureClassLoader

ClassLoader

2. ClassLoader重要方法loadclass()代碼解讀。

直接上代碼,代碼上注釋有說(shuō)明。

```
public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}

protected Class<?> loadClass(String name, boolean resolve) //resolve字段表示是否進(jìn)行【連接】階段處理
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // First, check if the class has already been loaded
        // 首先,判斷該類是否已經(jīng)加載過(guò)了。
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) { //如果父類存在
                    // 如果未加載過(guò),則委派給父類進(jìn)行加載。
                    c = parent.loadClass(name, false);
                } else {
                    // 如果父類不存在,則交給BootstrapClassLoader來(lái)加載。 什么時(shí)候父類不存在呢?其實(shí)就是ExtClassLoader不存在父類的情況。
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
                // 如果父類通過(guò)緩存+加載都無(wú)法找到,并拋出ClassNotFoundException異常時(shí),則捕獲異常但不處理。
            }

            if (c == null) {
                // If still not found, then invoke findClass in order
                // to find the class.                   
                long t1 = System.nanoTime();
                // 如果委托的父類們都無(wú)法找到該類,則本加載器自己親自動(dòng)手去查找。
                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;
    }
}
```

代碼中有幾個(gè)關(guān)鍵調(diào)用需要注意:

Class<?> c = findLoadedClass(name)通過(guò)緩存查找判斷是否存在該類。
  進(jìn)一步查看該方法實(shí)現(xiàn),又調(diào)用了native findLoadedClass0方法。
    ```
    protected final Class<?> findLoadedClass(String name) {
        if (!checkName(name))
            return null;
        return findLoadedClass0(name);
    }

    private native final Class<?> findLoadedClass0(String name);
    ```
② 當(dāng)parent != null時(shí),c = parent.loadClass(name, false);。如果父類不為空,則委派給父類的loadClass()方法執(zhí)行。
當(dāng) parent == null是,```c = findBootstrapClassOrNull(name);```父類如果為空時(shí),則委派給BootstrapClassLoader來(lái)查找。

這里就是雙親委派模型出現(xiàn)了。

③ 當(dāng)在經(jīng)過(guò)父類們緩存查找和加載后,仍然未找到該類,則本加載器會(huì)親自進(jìn)行查找c = findClass(name);。這個(gè)方法很關(guān)鍵。
    ```
    protected Class<?> findClass(String name) throws ClassNotFoundException {
            throw new ClassNotFoundException(name);
        }
    ```

3. 雙親委派模型的驗(yàn)證

    public static void main(String[] args) {
        ClassLoader loader = TestStatic3.class.getClassLoader();
        System.out.println(loader);
        System.out.println(loader.getParent());
        System.out.println(loader.getParent().getParent());
    }

輸出結(jié)果:

sun.misc.Launcher$AppClassLoader@b4aac2
sun.misc.Launcher$ExtClassLoader@193b845
null

4. 雙親委派模型的優(yōu)點(diǎn)

這里補(bǔ)充下幾個(gè)雙親委派模型的特點(diǎn)。

  • 系統(tǒng)類防止內(nèi)存中出現(xiàn)多份同樣的字節(jié)碼
    因?yàn)镴ava類隨著它的類加載器一起具備了一種帶有優(yōu)先級(jí)的層次關(guān)系。雙親委派模型很好的解決了各個(gè)類加載器的基礎(chǔ)類的統(tǒng)一問(wèn)題(越基礎(chǔ)的類由越上層的加載器進(jìn)行加載)。
  • 保證Java程序安全穩(wěn)定運(yùn)行
    使用雙親委派模型來(lái)組織類加載器之間的關(guān)系,有一個(gè)顯而易見(jiàn)的好處就是Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級(jí)的層次關(guān)系。例如,類java.lang.Object,它存放在rt.jar中,無(wú)論哪一個(gè)類加載器要加載這個(gè)了類,最終都是委派給模型最頂端的啟動(dòng)類加載器進(jìn)行加載,因此Object類在程序的各個(gè)類加載器環(huán)境中都是同一個(gè)類。
    相反,如果沒(méi)有使用雙親委派模型,由各個(gè)類加載器自行去加載的話,如果用戶自己編寫了一個(gè)稱為java.lang.Object的類,并放在程序的ClassPath中,那系統(tǒng)中將會(huì)出現(xiàn)多個(gè)不同的Object類,Java類型體系中最基本的行為也就無(wú)法保證,應(yīng)用程序也會(huì)變得一片混亂。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容