雙親委派模型

一、類加載器

1. 作用

實現(xiàn) 通過一個類的全限定名來獲取描述該類的二進制字節(jié)流 動作仔涩,即類的加載動作。

在虛擬機中粘舟,每個類加載器都有一個獨立的類名稱空間熔脂,故只有在 兩個類的類的全限定名相同佩研,且加載該類的加載器相同 的情況下,才判定相等(包括 equals()霞揉、isAssignableFrom()旬薯、isInstance() 方法及 instanceOf 關(guān)鍵字的判斷結(jié)果)。

2. 分類

啟動類加載器 (Bootstrap Class Loader)

負責(zé)加載存放在 <JAVA_HOME>\lib 目錄适秩,或者被 -Xbootclasspath 參數(shù)所指定的路徑中存放的绊序,且文件名能被識別的類庫(如 rt.jartools.jar秽荞,文件名不符合目錄正確也不會被加載)加載到 JVM 內(nèi)存中骤公。此加載器無法被 Java 程序直接使用,自定義類加載器若需要委派加載請求給此加載器加載蚂会,直接使用 null 代替即可淋样。

擴展類加載器(Extension Class Loader)

負責(zé)加載 <JAVA_HOME>\lib\ext 目錄中,或者被 java.ext.dirs 系統(tǒng)變量所指定路徑中的所有類庫胁住。此類庫中存放具有通用性的擴展類庫趁猴,且允許用戶自行添加,即擴展機制彪见。在類 sun.misc.Launcher$ExtClassLoader 中以 Java 代碼形式實現(xiàn)儡司,故用戶可直接在程序中使用此類加載器加載 Class 文件。JDK 9 中余指,此擴展類加載器被平臺類加載器替代捕犬。

平臺類加載器(Platform Class Loader)

由于模塊化系統(tǒng)中,整個 JDK 都基于模塊化構(gòu)建酵镜,故Java 類庫為滿足模塊化需求碉碉,未保留 <JAVA_HOME>\lib\ext 目錄,擴展類加載器也被替換為平臺類加載器淮韭。

應(yīng)用程序類加載器(Application Class Loader)

負責(zé)加載用戶類路徑(ClassPath)上所有類庫垢粮,開發(fā)者可直接使用此類加載器。由于此加載器在 ClassLoader 類中是方法getSystemClassLoader() 的返回值靠粪,故又稱系統(tǒng)類加載器蜡吧。若用戶未自定義加載器,一般情況下為默認加載器占键。

自定義類加載器

可通過重寫 ClassLoader 類的 findClass() 方法實現(xiàn)自定義類加載器昔善,以完成某些功能。

二畔乙、雙親委派模型

1. 描述

如果一個類加載器收到了類加載的請求君仆,它不會加載自己嘗試加載此類,而是委派請求給父類加載器進行加載。

2. 意義

共享

使 Java 類隨著它的類加載器一起具備了一種 帶有優(yōu)先級的層次關(guān)系返咱,通過這種層級關(guān)可以避免類的重復(fù)加載氮帐,當(dāng)父類加載器已經(jīng)加載了該類時,子 ClassLoader 就沒有必要再加載一次洛姑。

隔離

隔離功能,保證核心類庫的純凈和安全皮服,防止惡意加載楞艾,避免了 Java 的核心 API 被篡改。

保證唯一

若不采用雙親委派機制龄广,同一個類有可能被多個類加載器加載硫眯,這樣該類會被識別為兩個不同的類。

雙親委派機制在很大程度上防止內(nèi)存中出現(xiàn)多個相同的字節(jié)碼文件择同,加載類的時候默認會使用當(dāng)前類的 ClassLoader 進行加載两入,只有當(dāng)你使用該 class 的時候才會去裝載,一個加載器只會裝載同一個 class 一次敲才。

3. 源碼

源碼比較簡單裹纳,全部集中在 java.lang.ClassLoaderloadClass() 方法中。

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) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // 如果父類加載器拋出 ClassNotFoundException剃氧,說明父類加載器無法完成加載請求
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // 在父類加載器無法加載時,再調(diào)用本身的 findClass 方法進行類加載
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // 記錄統(tǒng)級信息
                    ...
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

先檢查請求加載的類型是否已加載過阻星,若沒有則調(diào)用父加載器的 loadClass() 方法朋鞍;若父類加載器為空則默認使用啟動類作為父加載器。若父類加載器加載失敗拋出 ClassNotFoundException 異常妥箕,才調(diào)用自己的 findClass() 方法嘗試進行加載滥酥。

4. 雙親委派模型圖

圖1. JDK1.8 雙親委派模型

如圖,即為 JDK 1.8 及以前的雙親委派模型圖畦幢,除頂層類加載器外坎吻,其余類加載器都必須有自己的父類加載器。類加載器的父子關(guān)系一般 不以繼承關(guān)系 實現(xiàn)呛讲,而是 組合關(guān)系 復(fù)用父加載器代碼禾怠。

圖2. JDK 9 雙親委派模型

JDK 9 中因模塊化的加入而重構(gòu)了目錄結(jié)構(gòu),也順帶將擴展類加載器替換為平臺類加載器贝搁。雖然總體上仍保持三層類加載器和雙親委派架構(gòu)吗氏,但委派關(guān)系發(fā)生變動。

當(dāng)平臺及應(yīng)用程序類加載器收到類加載請求雷逆,在委派給父類加載器前弦讽,要先 判斷是否歸屬于某一個系統(tǒng)模塊,如果找到歸屬關(guān)系,則優(yōu)先委派給對應(yīng)模塊的類加載器往产。由此被碗,也可以算是類加載器的 第四次被破壞

三仿村、雙親委派模型的三次破壞

雙親委派模型僅僅是 Java 設(shè)計者推薦開發(fā)者們的類加載器實現(xiàn)方式锐朴,并不是強制約束的模型。截至目前蔼囊,大多數(shù) Java 圈的類加載器都遵循此模型焚志,但仍出現(xiàn)過三次較大規(guī)模破壞。

1. 兼容 JDK 1.2 前的程序

產(chǎn)生原因

由于雙親委派模型是 JDK 1.2 才被引入畏鼓,但 Java 第一個版本即存在抽象類 java.lang.ClassLoader酱酬,開發(fā)者已編寫好自定義類加載器,若進行 JDK 升級云矫,則會導(dǎo)致 loadClass() 被覆蓋膳沽,而正確做法應(yīng)為重寫 findClass()

解決方案

為了兼容已存在的用戶自定義類让禀,Java 設(shè)計者們只能在 JDK 1.2 后添加一個新的 protected 方法 findClass()挑社,并引導(dǎo)用戶盡可能在類加載邏輯中重寫此方法,而不是在 loadClass() 中編寫代碼巡揍。按照 loadClass() 方法邏輯滔灶,父類加載失敗,會調(diào)用自己的 findClass() 方法完成加載吼肥,保證新代碼也可以符號雙親委派規(guī)則录平。

2. 自身的缺陷

產(chǎn)生原因

雙親委派模型很好地解決了各個類加載器協(xié)作時基礎(chǔ)類型一致性問題,即越基礎(chǔ)的類由越上層的類加載器加載缀皱。但基礎(chǔ)類型也會存在調(diào)用回用戶代碼的場景斗这。

場景

典型的例子便是 JNDI 服務(wù),此服務(wù)已是 Java 標準服務(wù)啤斗。它的代碼由啟動類加載器完成加載(即在 rt.jar 中)表箭,屬于 Java 中很基礎(chǔ)的類型。但 JNDI 存在的目的就是對資源進行查找和集中管理钮莲,故需要調(diào)用其他廠商實現(xiàn)并部署在應(yīng)用程序 ClassPath 下的 JNDI 服務(wù)提供者接口(SPI)免钻,但啟動類不可能識別且加載這些代碼。

解決方案

為解決此問題崔拥,Java 設(shè)計團隊引入了線程上下文類加載器极舔。此加載器可通過 java.lang.Thread 類的 setContextClassLoader() 方法進行設(shè)置,如果創(chuàng)建線程時未設(shè)置链瓦,它將從父類繼承一個拆魏,如果應(yīng)用程序全局范圍內(nèi)都未設(shè)置盯桦,則這個類加載器默認為應(yīng)用程序類加載器。故以此即可加載所需的 SPI 服務(wù)代碼渤刃。此方式為一種父類加載器請求子類加載器完成類加載的行為拥峦。

3. 實現(xiàn)程序動態(tài)性

產(chǎn)生原因

程序動態(tài)性即代碼熱替換、模塊熱部署等功能卖子。

場景

OSGi 是實現(xiàn)熱部署的常用規(guī)范略号,其實現(xiàn)熱部署的關(guān)鍵是它自定義的類加載器機制的實現(xiàn),每一個程序模塊(在 OSGi 中稱為 Bundle)都有一個類加載器洋闽,當(dāng)需要更換一個 Bundle 時璃哟,就把 Bundle 連同類加載器一起換掉以實現(xiàn)代碼熱替換。

實現(xiàn)方式

OSGi 環(huán)境下喊递,類加載器不再是雙親委派模型推薦的樹狀結(jié)構(gòu),而是更加復(fù)雜的網(wǎng)狀結(jié)構(gòu)阳似,它的委派關(guān)系僅少部分遵守雙親委派模型骚勘,其余部分會在平級類加載器中查找。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末撮奏,一起剝皮案震驚了整個濱河市俏讹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌畜吊,老刑警劉巖泽疆,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異玲献,居然都是意外死亡殉疼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門捌年,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓢娜,“玉大人,你說我怎么就攤上這事礼预∶呃” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵托酸,是天一觀的道長褒颈。 經(jīng)常有香客問我,道長励堡,這世上最難降的妖魔是什么谷丸? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮应结,結(jié)果婚禮上淤井,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好币狠,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布游两。 她就那樣靜靜地躺著,像睡著了一般漩绵。 火紅的嫁衣襯著肌膚如雪贱案。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天止吐,我揣著相機與錄音宝踪,去河邊找鬼。 笑死碍扔,一個胖子當(dāng)著我的面吹牛瘩燥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播不同,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼厉膀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了二拐?” 一聲冷哼從身側(cè)響起服鹅,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎百新,沒想到半個月后企软,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡饭望,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年仗哨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铅辞。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡藻治,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出巷挥,到底是詐尸還是另有隱情桩卵,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布倍宾,位于F島的核電站雏节,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏高职。R本人自食惡果不足惜钩乍,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望怔锌。 院中可真熱鬧寥粹,春花似錦变过、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至阔拳,卻和暖如春崭孤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背糊肠。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工辨宠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人货裹。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓嗤形,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容