Java中雙親委派機制的實現原理

類加載相關文章索引:
一文淺析Java中類加載過程
一文弄懂Java中類加載器的關係
Java中自定義類加載器

又是熱愛學習的一天!
在這裏插入圖片描述

雙親委派模型(Parents Delegation Model)

在上一篇文章中(Java中類加載器的關係)我們瞭解到,應用程序都是由3種類加載器相互配合工作的。如果有要求,還可以加上自定義類加載器。而這些類加載器之間的關係如下圖所示:
在這裏插入圖片描述

圖中展示的類加載器之間的這種層次關係,有個專業的名稱,叫做:雙親委派模型(Parents Delegation Model)。雙親委派模型要求除了頂層的啓動類加載器(Bootstrap ClassLoader)外,其他的類加載器都應該有自己的父類加載器。

在上文中已經解釋了 Application ClassLoader、Extension ClassLoader 和 Bootstrap ClassLoader 的關係。而自定義的類加載器的父加載器就是 Application ClassLoader。

雙親委派的機制定義

如果一個類加載器收到了類加載的請求,它首先不會自己嘗試去加載這類,而是把這個請求委派給父加載器去嘗試加載,每一層級的類加載器都是如此。因爲所有的加載請求都應該委派到頂層的啓動類加載器中,只有當父加載器反饋自己無法完成這個加載請求時,子類加載器纔會去嘗試加載。

有這樣的規則是爲了保護我們程序的安全。

雙親外派機制的好處

使用雙親委派模型來組織類加載器之間的關係,有一個明顯的好處就是Java類隨着它的類加載器一起具備了一種帶有優先級的層次關係。這樣就能保證一個類在虛擬機裏的唯一性。
如果我們沒有使用雙親委派機制來進行類加載動作,用戶自己創建了一個叫做 java.lang.Object 的類,並放在程序的 classpath 中,那系統就會有多個不同的 Object 類。那麼Java體系中最基礎的行爲也就無法得到保障。

雙親委派模型的實現原理

雙親委派模型的實現非常簡單,實現雙親委派模型的代碼都集中在 java.lang.ClassLoader 的 loadClass() 方法之中。邏輯清晰易懂,大體流程就是:

  1. 首先檢查這個類是否已經被加載過了(是否在虛擬機中已經存在了),若已經加載了,就直接進返回。
  2. 若沒有加載,則調用父類加載器的 loadClass() 方法去嘗試加載。
  3. 如父類加載器爲空,則使用啓動類加載器去嘗試加載。
  4. 如果父類加載器加載失敗,則拋出 ClassNotFoundException 異常後,使用自己的 findClass() 方法進行加載。

碼解

下面是 loadClass() 方法的源碼,整個雙親委派模型的實現都在這個方法中體現出來了:

    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 首先,檢查請求的類是否已經被加載過了。
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
					// 如果父類不爲空,則調用父類加載器的 loadClass() 方法進行加載。
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else { 
						// 如果父類爲空,則使用啓動類加載器去嘗試加載。
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // 如果父類加載器拋出 ClassNotFoundException
                    // 說明父加載器無法完成加載請求
                }

                if (c == null) {
                    // 在父類加載器無法加載的時候
                    // 調用自己的 findClass() 方法進行類加載
                    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;
        }
    }

如果代碼還不夠清楚的話,下面將使用圖的形式來進行說明:

圖示

雙親委派機制的圖示如下:
在這裏插入圖片描述

明白了雙親委派機制之後,我們就可以自定義類加載器來玩出一些花兒來了。


技 術 無 他, 唯 有 熟 爾。
知 其 然, 也 知 其 所 以 然。
踏 實 一 些, 不 要 着 急, 你 想 要 的 歲 月 都 會 給 你。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章