類加載機制ClassLoader簡介

??ClassLoader在Java中有著非常重要的作用,它主要工作在Class裝載的加載階段,其主要作用是從系統外部獲得Class二進制數據流。ClassLoader是Java的核心組件,所有的Class都是由ClassLoader進行加載的,ClassLoader負責通過各種方式將Class信息的二進制數據流讀入系統,然后交給Java虛擬機進行連接、初始化等操作。因此,ClassLoader在整個裝載階段,只能影響到類的加載,而無法通過ClassLoader去改變類的連接和初始化行為。
??從代碼層次看,ClassLoader是一個抽象類,它提供了一些重要的接口,用于自定義Class的加載流程和加載方式。ClassLoader的主要方法如下:

  • public Class<?> loadClass(String name) throws ClassNotFoundException

    給定一個類名,加載一個類,返回代表這個類的Class實例,如果找不到類,則返回ClassNotFoundException異常

  • protected final Class<?> defineClass(byte[] b,int off,int len)

    根據給定的字節碼流b定義一個類,off和len參數表示實際Class信息在byte數組中的位置和長度,其中byte數組b是ClassLoader從外部獲取的。這是受保護的方法,只有在自定義ClassLoader子類中可以使用

  • protected Class<?> findClass(String name) throws ClassNotFoundException

    查找一個類,這是一個受保護的方法,也是重載ClassLoader時,重要的系統擴展點。這個方法會在loadClass()時被調用,用于自定義查找類的邏輯。如果不需要修改類加載默認機制,只是想改變類加載的形式就可以重載該方法

  • protected final Class<?> findLoadedClass(String name)

    這也是一個受保護的方法,它會去尋找已經加載的類。這個方法是final方法,無法被修改

??在ClassLoader的結構中,還有一個重要的字段parent,它也是一個ClassLoader的實例,這個字段所表示的ClassLoader也稱為這個ClassLoader的雙親。在類加載的過程中,ClassLoader可能會將某些請求交予自己的雙親處理。

ClassLoader的分類

&nbap;?在標準的Java程序中,Java虛擬機會創建3類ClassLoader為整個應用程序服務。它們分別是:BootStrapClassLoader(啟動類加載器)、ExtensionClassLoader(擴展類加載器)和AppClassLoader(應用類加載器,也稱為系統類加載器)。此外,每個應用程序還可以擁有自定義的ClassLoader,擴展Java虛擬機獲取Class數據的能力。

??各個ClassLoader的層次和功能如下圖所示,從ClassLoader的層次自頂往下為啟動類加載器、擴展類加載器、應用類加載器和自定義類加載器。其中,應用類加載器的雙親為擴展類加載器,擴展類加載器的雙親為啟動類加載器。當系統需要使用一個類時,在判斷類是否已經被加載時,會先從當前底層類加載器進行判斷。當系統需要加載一個類時,會從頂層類開始加載,依次向下嘗試,直到成功。


??在這些ClassLoader中,啟動類加載器最為特別,它是完全由C代碼實現的,并且在Java中沒有對象與之對應。系統的核心類就是由啟動類加載器進行加載的,它也是虛擬機的核心組件。擴展類加載器和應用類加載器都有對應的Java對象可供使用。

??無法在Java代碼中直接訪問啟動類加載器,因為這是一個純C實現,因此任何加載在啟動類加載器中的類是無法獲得其ClassLoader實例的,比如:

String.class.getClassLoader()

由于String屬于Java核心類,由啟動類加載器加載,故以上代碼返回的是null。

ClassLoader的雙親委托模式

??系統中的ClassLoader在協同工作時,默認會使用雙親委托模式。即在類加載的時候,系統會判斷當前類是否已經被加載,如果已經被加載,就會直接返回可用的類,否則就會嘗試加載,在嘗試加載時,會先請求雙親處理,如果雙親請求失敗,則會自己加載。

注意:雙親為null有兩種情況:第一,其雙親就是啟動類加載器;第二,當前加載器就是啟動類加載器。判斷類是否加載時,應用類加載器會順著雙親路徑往上判斷,直到啟動類加載器。但是啟動類加載器不會往下詢問,這個委托是單向的。

雙親委托模式的弊端

??前文提到,檢查類是否加載的委托過程是單向的,這個方式雖然從結構上說比較清晰,使各個ClassLoader的職責非常明確,但是同時會帶來一個問題,即頂層的ClassLoader無法訪問底層的ClassLoader所加載的類。

??通常情況下,啟動類加載器中的類為系統核心類,包括一些重要的系統接口,而在應用類加載器中,為應用類。按照這種模式,應用類訪問系統類自然是沒有問題,但是系統類訪問應用類就會出現問題。比如在系統類中提供了一個接口,該接口需要在應用類中得以實現,該接口還綁定一個工廠方法,用于創建該接口的實例,而接口和工廠方法都在啟動類加載器中。這時,就會出現該工廠方法無法創建由應用類加載器加載的應用實例的問題。

雙親委托模式的補充

??在Java平臺中,把核心類(rt.jar)中提供外部服務,可由應用層自行實現的接口,通常可以稱為Service Provider Interface,即SPI。
??為了解決啟動類加載器無法訪問應用類加載器加載的類的問題,Java中通過把一個ClassLoader置于一個線程實例中,這個ClassLoader叫做上下文加載器,使該ClassLoader成為一個相對共享的實例。默認情況下,上下文加載器就是應用類加載器,這樣即使是在啟動類加載器中的代碼也可以通過這種方式訪問應用類加載器的類,其示意圖如下所示:


突破雙親模式

??雙親模式的類加載方式是虛擬機默認的行為,但并非必須這么做,通過重載ClassLoader可以修改該行為。事實上,不少應用軟件和框架都修改了這種行為,比如Tomcat和OSGi框架,都有各自獨特的類加載順序。具體的過程就不嗷述了,感興趣的可以取查閱資料。

熱替換的實現

??熱替換是指在程序的運行過程中,不停止服務,只通過替換程序文件來修改程序的行為。熱替換的關鍵需求在于服務不能中斷,修改必須立即表現正在運行的系統之中。基本上大部分腳本語言都是天生支持熱替換的,比圖PHP,只要替換了PHP源文件,這種改動就會立即生效,而無需重啟Web服務器。

??但對Java來說,熱替換并非天生就支持,如果一個類已經加載到系統中,通過修改類文件,并無法讓系統再來加載并重定義這個類。因此,在Java中實現這一功能的一個可行的方法就是靈活運用ClassLoader。

注意:由不同ClassLoader加載的同名類屬于不同的類型,不能相互轉換和兼容。即兩個不同的ClassLoader加載同一個類,在虛擬機內部,會認為這2個類是完全不同的。

??根據這個特點,可以用來模擬熱替換的實現,基本思路如下圖所示:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,048評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,414評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,169評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,722評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,465評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,823評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,813評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,000評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,554評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,295評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,513評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,722評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,125評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,430評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,237評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,482評論 2 379

推薦閱讀更多精彩內容