您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關java的類加載器有哪些,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
一、類與類加載器
類加載器:實現加載階段的第一步,通過一個類的全限定名來將這個類的二進制字節流加載進jvm。
類與類加載器:任意一個類唯一性都是由它本身和加載它的類加載器確定,兩個類是否相等在它們是由同一個類加載器加載的前提下。
jvm虛擬機中包括兩種類加載器:一種是啟動類加載器(Bootstrap ClassLoader
),它是使用C++實現;另一種是其他所有用java實現的類加載器。
從java程序角度:
1)啟動類加載器:負責加載<JAVA_HOME>\lib目錄下或者被-Xbootclasspath參數所指定的路徑中的類,此外要求文件名被虛擬機識別,如果不被jvm識別也無法被加載。
2)擴展類加載器:負責加載<JAVA_HOME>\lib\exit目錄下或者被java.exit.dirs系統變量所指定的路徑中的所有類庫。
3)應用程序類加載器(系統類加載器):它是Classloader中的getSystemClassloader()方法的返回值。負責加載用戶類路徑上所指定的類庫,如果應用程序中沒有自定義類加載器,這個就為程序中默認的類加載器。
二、雙親委派模型
除了頂層的啟動類加載器,其余所有類加載器都有自己的父類加載器。父子關系不以繼承實現,而是以組合關系來復用父類加載器。
工作過程: 類加載器接到類加載請求–>將請求委派給父類加載器(直到最頂層啟動類加載器)–>父類嘗試加載,加載失敗反饋給子類加載器–>子類加載器嘗試加載
雙親委派模型的好處:保證java底層API的穩定,避免加載和基本類重名(Object)的自定義類導致出現多個不同的重名的類(Object),從而造成java基礎行為的混亂。
雙親委派模型源碼:
方法加同步鎖保證線程安全,首先檢查該類是否被加載過,如果沒有加載則調用父類加載器的loadClass()方法,若父類加載器為空說明是啟動類加載器,則調用啟動類加載器。
如果父類加載失敗會拋出ClassNotFoundException,在調用自己的findClass()方法進行加載。
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { //同步鎖 synchronized (getClassLoadingLock(name)) { // 首先檢車這個類是不是已被加載 Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { //如果父類不為空則調用父類加載器的loadClass方法 c = parent.loadClass(name, false); } else { //沒有父類則默認調用啟動類加載器加載 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { //如果父類加載器找不到這個類則拋出ClassNotFoundException } if (c == null) { // 父類加載器失敗時調用自身的findClass方法加載 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; } }
三、破壞雙親委派模型
1.第一次破壞
雙親委派模型出現在JDK1.2之后,而類加載器和抽象類java.lang.ClassLoader已經存在。
因此為了向前兼容,JDK1.2之后在ClassLoader中添加了一個新的protected方法findClass。用戶把自己的類加載邏輯寫在findClass方法中,而不是重寫loadClass方法,從而保證自定義的類加載符合雙親委派模型。
2.第二次破壞
模型自身有缺陷。雙親委派可以確保各個類加載器的基礎類的統一,這是在用戶代碼調用基礎類的情況下,如果出現基礎類回調用戶代碼那就不適用了。比如涉及到SPI的場景去加載所需要的SPI代碼。
SPI機制的介紹參考其他文章。
為了解決這個問題,引入了線程上下文加載器(Thread Context ClassLoader),這個類加載器就可以通過java.lang.Thread類中的setContextClassLoader()方法進行設置,如果創建線程時未設置將會從父線程中繼承一個,如果全局都沒有則默認就是應用程序類加載器,利用這個加載器可以完成父類加載器請求子類加載器加載的動作。
3.第三次破壞
由于對程序動態性追求導致,如熱部署,熱替換等。
比如模塊化標準OSGi R4.2中將雙親委派的樹形結構變成了更復雜的網狀結構。
看完上述內容,你們對java的類加載器有進一步的了解嗎?如果還想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。