雙親委派機制
雙親委派機制是指當一個類加載器收到一個類加載請求時,該類加載器首先會把請求委派給父類加載器。每一個類加載器都是如此(遞歸的去查找),只有在父類加載器在本身的搜索範圍內找不到指定類時,子類加載器纔會嘗試本身去加載。
顯然,在介紹雙親委派機制的時候,不得不提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 ClassLoader
和Application 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」獲取電子書合集,也可簽到領現金紅包。