Android插件化開發(fā)核心類ClassLoader相關(guān)詳解

最近在研究插件化開發(fā),順便就了解了 ClassLoader 這個類加載器刃宵,順藤摸瓜级乍,查到了jvm里面的雙親委派模型,這里就簡單的講一下什么是預(yù)定義類加載器和雙親委派模型竣贪?

學好java基礎(chǔ)军洼,順便學好jvm虛擬機巩螃,對閱讀源碼和插件化開發(fā)很有幫助。

1匕争、預(yù)定義類加載器

JVM預(yù)定義的三種類型類加載器:

  • 1.啟動(Bootstrap)類加載器:是用本地代碼實現(xiàn)的類裝入器避乏,它負責將 <Java_Runtime_Home>/lib 下面的類庫加載到內(nèi)存中(比如 rt.jar)。由于引導類加載器涉及到虛擬機本地實現(xiàn)細節(jié)甘桑,開發(fā)者無法直接獲取到啟動類加載器的引用拍皮,所以不允許直接通過引用進行操作。

  • 2.標準擴展(Extension)類加載器:是由 Sun 的 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)實現(xiàn)的扇住。它負責將 < Java_Runtime_Home >/lib/ext 或者由系統(tǒng)變量 java.ext.dir 指定位置中的類庫加載到內(nèi)存中春缕。開發(fā)者可以直接使用標準擴展類加載器盗胀。

  • 3.系統(tǒng)(System)類加載器:是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)實現(xiàn)的艘蹋。由于這個類加載器是 ClassLoader 中的 getSystemClassLoader() 方法的返回值,所以一般也被稱為系統(tǒng)類加載器票灰。它負責將系統(tǒng)類路徑(CLASSPATH)中指定的類庫加載到內(nèi)存中女阀。開發(fā)者可以直接使用系統(tǒng)類加載器,如果應(yīng)用程序中沒有自定義過自己的類加載器屑迂,一般情況下這個就是程序中默認的類加載器浸策。

除了以上列舉的三種類加載器,還有一種比較特殊的類型 — 線程上下文類加載器惹盼。

應(yīng)用程序由這三種類加載器互相配合進行加載的庸汗,如果有必須,還可以加入自己定義的類加載器手报。這些類加載器之間的關(guān)系一般如下圖:

類加載器之間的關(guān)系

2蚯舱、雙親委派模型(雙親委派機制)

雙親委派模型要求除了頂層的啟動類加載器之外,其余的類加載器都應(yīng)當有自己的父類加載器掩蛤。這里的類加載器之間的父子關(guān)系一般不會以繼承的關(guān)系來實現(xiàn)枉昏,而是使用組合關(guān)系來復(fù)用父加載器的代碼。

雙親委派模型的式作過程是:如果一個類加載器收到了類加載的請求揍鸟,它首先不會自己去嘗試加載這個類兄裂,而是把這個請求委派給父類加載器去完成,每一個層次的類加載器都是如此阳藻,因此所有的加載請求最終都應(yīng)該傳送到頂層的啟動類加載器中晰奖,只有當父加載器反饋自己無法完全這個加載請求時,子加載器才會嘗試自己去加載腥泥。

3匾南、雙親委派模型的破壞

  • 1、第1次“被破壞”

??雙親委派模型的第一次“被破壞”其實發(fā)生在雙親委派模型出現(xiàn)之前--即JDK1.2發(fā)布之前道川。由于雙親委派模型是在JDK1.2之后才被引入的午衰,而類加載器和抽象類 java.lang.ClassLoader 則是JDK1.0時候就已經(jīng)存在立宜,面對已經(jīng)存在 的用戶自定義類加載器的實現(xiàn)代碼,Java設(shè)計者引入雙親委派模型時不得不做出一些妥協(xié)臊岸。為了向前兼容橙数,JDK1.2之后的 java.lang.ClassLoader 添加了一個新的 proceted 方法 findClass() ,在此之前帅戒,用戶去繼承 java.lang.ClassLoader 的唯一目的就是重寫 loadClass() 方法灯帮,因為虛擬在進行類加載的時候會調(diào)用加載器的私有方法 loadClassInternal(),而這個方法的唯一邏輯就是去調(diào)用自己的 loadClass() 逻住。JDK1.2之后已不再提倡用戶再去覆蓋 loadClass() 方法钟哥,應(yīng)當把自己的類加載邏輯寫到 findClass() 方法中,在 loadClass() 方法的邏輯里瞎访,如果父類加載器加載失敗腻贰,則會調(diào)用自己的findClass()方法來完成加載,這樣就可以保證新寫出來的類加載器是符合雙親委派模型的扒秸。

  • 2播演、第2次“被破壞”

??雙親委派模型的第二次“被破壞”是這個模型自身的缺陷所導致的,雙親委派模型很好地解決了各個類加載器的基礎(chǔ)類統(tǒng)一問題(越基礎(chǔ)的類由越上層的加載器進行加載)伴奥,基礎(chǔ)類之所以被稱為“基礎(chǔ)”写烤,是因為它們總是作為被調(diào)用代碼調(diào)用的API。但是拾徙,如果基礎(chǔ)類又要調(diào)用用戶的代碼洲炊,那該怎么辦呢。

??這并非是不可能的事情尼啡,一個典型的例子便是JNDI服務(wù)暂衡,它的代碼由啟動類加載器去加載(在JDK1.3時放進 rt.jar ),但JNDI的目的就是對資源進行集中管理和查找玄叠,它需要調(diào)用獨立廠商實現(xiàn)部部署在應(yīng)用程序的classpath下的JNDI接口提供者 (SPI, Service Provider Interface) 的代碼古徒,但啟動類加載器不可能“認識”之些代碼,該怎么辦读恃?

??為了解決這個困境隧膘,Java設(shè)計團隊只好引入了一個不太優(yōu)雅的設(shè)計:線程上下文件類加載器(Thread Context ClassLoader)。這個類加載器可以通過 java.lang.Thread 類的 setContextClassLoader() 方法進行設(shè)置寺惫,如果創(chuàng)建線程時還未設(shè)置疹吃,它將會從父線程中繼承一個;如果在應(yīng)用程序的全局范圍內(nèi)都沒有設(shè)置過西雀,那么這個類加載器默認就是應(yīng)用程序類加載器萨驶。了有線程上下文類加載器,JNDI服務(wù)使用這個線程上下文類加載器去加載所需要的SPI代碼艇肴,也就是父類加載器請求子類加載器去完成類加載動作腔呜,這種行為實際上就是打通了雙親委派模型的層次結(jié)構(gòu)來逆向使用類加載器叁温,已經(jīng)違背了雙親委派模型,但這也是無可奈何的事情核畴。Java中所有涉及SPI的加載動作基本上都采用這種方式膝但,例如JNDI,JDBC,JCE,JAXB和JBI等。

  • 3谤草、第3次“被破壞”

??雙親委派模型的第三次“被破壞”是由于用戶對程序的動態(tài)性的追求導致的跟束,例如OSGi的出現(xiàn)。在OSGi環(huán)境下丑孩,類加載器不再是雙親委派模型中的樹狀結(jié)構(gòu)冀宴,而是進一步發(fā)展為網(wǎng)狀結(jié)構(gòu)。

4温学、幾點思考

  • 1略贮、Bootstrap類

Java虛擬機的第一個類加載器是Bootstrap,這個加載器很特殊枫浙,它不是Java類刨肃,因此它不需要被別人加載,它嵌套在Java虛擬機內(nèi)核里面箩帚,也就是JVM啟動的時候Bootstrap就已經(jīng)啟動,它是用C++寫的二進制代碼(不是字節(jié)碼)黄痪,它可以去加載別的類紧帕。

這也是我們在測試時為什么發(fā)現(xiàn)System.class.getClassLoader()結(jié)果為null的原因,這并不表示System這個類沒有類加載器桅打,而是它的加載器比較特殊是嗜,是BootstrapClassLoader,由于它不是Java類挺尾,因此獲得它的引用肯定返回null鹅搪。

  • 2、委托機制具體含義
    當Java虛擬機要加載一個類時遭铺,到底派出哪個類加載器去加載呢丽柿?

    • 首先當前線程的類加載器去加載線程中的第一個類(假設(shè)為類A)。
      注:當前線程的類加載器可以通過Thread類的getContextClassLoader()獲得魂挂,也可以通過setContextClassLoader()自己設(shè)置類加載器甫题。

    • 如果類A中引用了類B,Java虛擬機將使用加載類A的類加載器去加載類B涂召。

    • 還可以直接調(diào)用ClassLoader.loadClass()方法來指定某個類加載器去加載某個類坠非。

  • 3、委托機制的意義 — 防止內(nèi)存中出現(xiàn)多份同樣的字節(jié)碼
    比如兩個類A和類B都要加載System類:

    • 如果不用委托而是自己加載自己的果正,那么類A就會加載一份System字節(jié)碼炎码,然后類B又會加載一份System字節(jié)碼盟迟,這樣內(nèi)存中就出現(xiàn)了兩份System字節(jié)碼

    • 如果使用委托機制潦闲,會遞歸的向父類查找队萤,也就是首選用Bootstrap嘗試加載,如果找不到再向下矫钓。這里的System就能在Bootstrap中找到然后加載要尔,如果此時類B也要加載System,也從Bootstrap開始新娜,此時Bootstrap發(fā)現(xiàn)已經(jīng)加載過了System那么直接返回內(nèi)存中的System即可而不需要重新加載赵辕,這樣內(nèi)存中就只有一份System的字節(jié)碼了。

5概龄、一道面試題:能不能自己寫個類叫java.lang.System还惠?

  • 答案: 通常不可以,但可以采取另類方法達到這個需求私杜。

  • 解釋: 為了不讓我們寫System類蚕键,類加載采用委托機制,這樣可以保證爸爸們優(yōu)先衰粹,爸爸們能找到的類锣光,兒子就沒有機會加載。而System類是Bootstrap加載器加載的铝耻,就算自己重寫糠惫,也總是使用Java系統(tǒng)提供的System失暂,自己寫的System類根本沒有機會得到加載吮成。

但是蓝仲,我們可以自己定義一個類加載器來達到這個目的,為了避免雙親委托機制泡态,這個類加載器也必須是特殊的搂漠。由于系統(tǒng)自帶的三個類加載器都加載特定目錄下的類,如果我們自己的類加載器放在一個特殊的目錄某弦,那么系統(tǒng)的加載器就無法加載桐汤,也就是最終還是由我們自己的加載器加載。


參考文章:

深入理解Java虛擬機筆記---雙親委派模型
關(guān)于Java類加載雙親委派機制的思考(附一道面試題)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末刀崖,一起剝皮案震驚了整個濱河市惊科,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌亮钦,老刑警劉巖馆截,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡蜡娶,警方通過查閱死者的電腦和手機混卵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來窖张,“玉大人幕随,你說我怎么就攤上這事∷藿樱” “怎么了赘淮?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長睦霎。 經(jīng)常有香客問我梢卸,道長,這世上最難降的妖魔是什么副女? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任蛤高,我火速辦了婚禮,結(jié)果婚禮上碑幅,老公的妹妹穿的比我還像新娘戴陡。我一直安慰自己,他們只是感情好沟涨,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布恤批。 她就那樣靜靜地躺著,像睡著了一般拷窜。 火紅的嫁衣襯著肌膚如雪开皿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天篮昧,我揣著相機與錄音,去河邊找鬼笋妥。 笑死懊昨,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的春宣。 我是一名探鬼主播酵颁,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼月帝!你這毒婦竟也來了躏惋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤嚷辅,失蹤者是張志新(化名)和其女友劉穎簿姨,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡扁位,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年准潭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片域仇。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡刑然,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出暇务,到底是詐尸還是另有隱情泼掠,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布垦细,位于F島的核電站择镇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蝠检。R本人自食惡果不足惜沐鼠,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望叹谁。 院中可真熱鬧饲梭,春花似錦、人聲如沸焰檩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽析苫。三九已至兜叨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間衩侥,已是汗流浹背国旷。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留茫死,地道東北人跪但。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像峦萎,于是被迫代替她去往敵國和親屡久。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355

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