帶你看懂雙親委派,耗子尾汁

雙親委派機制
  雙親委派機制是指當一個類加載器收到一個類加載請求時,該類加載器首先會把請求委派給父類加載器。每一個類加載器都是如此(遞歸的去查找),只有在父類加載器在本身的搜索範圍內找不到指定類時,子類加載器纔會嘗試本身去加載。
顯然,在介紹雙親委派機制的時候,不得不提ClassLoader。再說ClassLoader以前,咱們得先了解下Java的基本知識。
Java是運行在Java的虛擬機(JVM)中的,可是它是怎麼就運行在JVM中了呢?咱們在IDE中編寫的Java源代碼被編譯器編譯成.class的字節碼文件。而後由咱們的ClassLoader負責將這些class文件加載到JVM中去執行。
JVM中提供了三層的ClassLoader:java

暖冬回血~~~~bootstrap

你們好,我是AIO生活,關注我,後續連載更多技術重難點,文章有不足之處,歡迎你們留言指正,謝謝你們啦!安全

順便提一下,幫你們整理了些JAVA電子書,掃碼回覆「1024」獲取電子書合集,也可簽到領現金紅包。ssh

Bootstrap ClassLoader(啓動類加載器):主要負責加載核心的類庫(java.lang.*等),構造Extension ClassLoaderApplication ClassLoader函數

Extension ClassLoader(擴展類加載器):主要負責加載jre/lib/ext目錄下的一些擴展的jar。spa

Application ClassLoader(應用程序類加載器):主要負責加載應用程序的主函數類。code

最後一個CustomClassLoader(用戶自定義類加載器)java編寫,用戶自定義的類加載器,可加載指定路徑的class文件
在這裏插入圖片描述對象

那若是有一個Hello.class文件是如何被加載到JVM中的呢?
咱們簡單看一下源碼blog

protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 首先檢查這個classsh是否已經加載過了
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // c==null表示沒有加載,若是有父類的加載器則讓父類加載器加載
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        //若是父類的加載器爲空 則說明遞歸到bootStrapClassloader了
                        //bootStrapClassloader比較特殊沒法經過get獲取
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {}
                if (c == null) {
                    //若是bootstrapClassLoader 仍然沒有加載過,則遞歸回來,嘗試本身去加載class
                    long t1 = System.nanoTime();
                    c = findClass(name);
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

上述這段代碼已經很好的解釋了雙親委派機制,爲了更容易理解,咱們先參看下面描述上述代碼流程的圖再談Hello.class如何加載:
在這裏插入圖片描述
從上圖中咱們就更容易理解了,當一個Hello.class這樣的文件要被加載時。不考慮咱們自定義類加載器,首先會在AppClassLoader中檢查是否加載過,若是有那就無需再加載了。若是沒有,那麼會拿到父加載器,而後調用父加載器的loadClass方法。父類中同理會先檢查本身是否已經加載過,若是沒有再往上。注意這個過程,直到到達Bootstrap ClassLoader以前,都是沒有哪一個加載器本身選擇加載的。若是父加載器沒法加載,會下沉到子加載器去加載,一直到最底層(其實就是遞歸查找過程),若是沒有任何加載器能加載,就會拋出ClassNotFoundException遞歸

因而,咱們就能夠很好的總結雙親委派機制的工做流程了:

  • 一、當Application ClassLoader收到一個類加載請求時,他首先不會本身去嘗試加載這個類,而是將這個請求委派給父類加載器Extension ClassLoader去完成。
  • 二、當Extension ClassLoader收到一個類加載請求時,他首先也不會本身去嘗試加載這個類,而是將請求委派給父類加載器Bootstrap ClassLoader去完成。
  • 三、若是Bootstrap ClassLoader加載失敗(在<JAVA_HOME>\lib中未找到所需類),就會讓Extension ClassLoader嘗試加載。
  • 四、若是Extension ClassLoader也加載失敗,就會使用Application ClassLoader加載。
  • 五、若是Application ClassLoader也加載失敗,就會使用Custom ClassLoader(用戶自定義加載器)去嘗試加載。
  • 六、若是均加載失敗,就會拋出ClassNotFoundException異常。

雙親委派機制的做用
一、防止重複加載同一個.class。經過委託去向上面問一問,加載過了,就不用再加載一遍。保證數據安全。
二、保證核心.class不能被篡改。經過委託方式,不會去篡改核心.class,即便篡改也不會去加載,即便加載也不會是同一個.class對象了。不一樣的加載器加載同一個.class也不是同一個Class對象。這樣保證了Class執行安全。

舉個栗子:若是有人想替換系統級別的類:String.java。篡改它的實現,可是在這種機制下這些系統的類已經被Bootstrap ClassLoader加載過了,因此並不會再去加載,從必定程度上防止了危險代碼的植入。

暖冬回血~~~~

你們好,我是AIO生活,關注我,後續連載更多技術重難點,文章有不足之處,歡迎你們留言指正,謝謝你們啦!

順便提一下,幫你們整理了些JAVA電子書,掃碼回覆「1024」獲取電子書合集,也可簽到領現金紅包。

相關文章
相關標籤/搜索