BiBi - JVM -9- 類(lèi)加載器

From:深入理解Java虛擬機(jī)

類(lèi)加載器定義

虛擬機(jī)在類(lèi)加載階段中的【通過(guò)一個(gè)類(lèi)的全限定名來(lái)獲取描述此類(lèi)的二進(jìn)制字節(jié)流】命咐,這個(gè)過(guò)程放到Java虛擬機(jī)外部去實(shí)現(xiàn)糜芳,以便讓?xiě)?yīng)用程序自己決定如何去獲取所需要的類(lèi)霍掺,實(shí)現(xiàn)這個(gè)過(guò)程的代碼模塊稱(chēng)為【類(lèi)加載器】赌蔑。

類(lèi)加載器最初是為了滿(mǎn)足Java Applet的需求而開(kāi)發(fā)的,現(xiàn)在Java Applet技術(shù)已經(jīng)落伍了搔确,但類(lèi)加載器技術(shù)卻得到了廣泛應(yīng)用彼棍。如:類(lèi)層次劃分、OSGi膳算、熱部署座硕、代碼加密等領(lǐng)域。

任意一個(gè)類(lèi)涕蜂,都需要由加載它的類(lèi)加載器和這個(gè)類(lèi)本身华匾,共同確定其在Java虛擬機(jī)中的唯一性。每一個(gè)類(lèi)加載器机隙,都有一個(gè)獨(dú)立的類(lèi)名空間蜘拉。即萨西,判斷類(lèi)是否相等、instanceof是基于同一個(gè)類(lèi)加載器而言的旭旭。

小例子:

Object obj = myLoader.loadClass("com.ljg.Test").newInstance();
System.out.println(obj.getClass()); //com.ljg.Test
System.out.println(obj instanceof com.ljg.Test); //false

盡管obj.getClass()返回com.ljg.Test谎脯,但instanceof結(jié)果為false。因?yàn)樘摂M機(jī)中存在兩個(gè)Test類(lèi)持寄,一個(gè)由系統(tǒng)應(yīng)用程序類(lèi)加載器加載的源梭,另一個(gè)由我們自定義的myLoader類(lèi)加載器加載的,雖然都來(lái)自同一個(gè)Class文件稍味,但依然是兩個(gè)獨(dú)立的類(lèi)废麻。

雙親委派模型

  1. 從Java虛擬機(jī)角度講,加載器分兩種:
    1)啟動(dòng)類(lèi)加載器仲闽,使用C++語(yǔ)言實(shí)現(xiàn)【針對(duì)HotSpot而言】,是虛擬機(jī)自身的一部分僵朗。
    2)其它的類(lèi)加載器赖欣,使用Java語(yǔ)言實(shí)現(xiàn),獨(dú)立于虛擬機(jī)之外验庙,并且都繼承抽象類(lèi)ClassLoader顶吮。

  2. 從Java開(kāi)發(fā)人員角度講,有三種重要的類(lèi)加載器:
    1)啟動(dòng)類(lèi)加載器
    加載<java_home>\lib目錄中的粪薛,并且是虛擬機(jī)識(shí)別的類(lèi)悴了。啟動(dòng)類(lèi)加載器無(wú)法被Java程序直接引用。
    2)擴(kuò)展類(lèi)加載器
    由ExtClassLoader實(shí)現(xiàn)违寿,加載<java_home>\lib\ext目錄中的類(lèi)湃交,開(kāi)發(fā)者可以直接使用擴(kuò)展類(lèi)加載器。
    3)應(yīng)用程序類(lèi)加載器
    由AppClassLoader實(shí)現(xiàn)藤巢,是getSystemClassLoader()方法的返回值搞莺,所以一般稱(chēng)為【系統(tǒng)類(lèi)加載器】。他負(fù)責(zé)加載用戶(hù)類(lèi)路徑上所定義的類(lèi)掂咒,開(kāi)發(fā)者可以直接使用這個(gè)類(lèi)加載器才沧。如果用戶(hù)沒(méi)有自定義類(lèi)加載器,會(huì)默認(rèn)使用個(gè)這個(gè)類(lèi)加載器绍刮。

雙親委派模型的過(guò)程:如果一個(gè)類(lèi)加載器收到了類(lèi)加載的請(qǐng)求温圆,它首先不會(huì)自己去加載這個(gè)類(lèi),而是把這個(gè)請(qǐng)求委派給父類(lèi)加載器去完成孩革,每一層的類(lèi)加載器都是如此岁歉,因此所有的加載請(qǐng)求最終都應(yīng)該傳送到頂層的【啟動(dòng)類(lèi)加載器】,只有當(dāng)父加載器反饋?zhàn)约簾o(wú)法完成這個(gè)加載請(qǐng)求時(shí)【即它的搜索范圍中沒(méi)有找到所需的類(lèi)】膝蜈,子加載器才會(huì)嘗試自己去加載刨裆。

注意:類(lèi)加載器之間的父子關(guān)系一般不是繼承澈圈,而是使用組合關(guān)系來(lái)復(fù)用父加載器。

雙親委派模型的好處

Java類(lèi)具有一種優(yōu)先級(jí)的層次關(guān)系帆啃。如:java.lang.Object瞬女,無(wú)論哪個(gè)類(lèi)加載器要加載這個(gè)類(lèi),最終都會(huì)委派給處于模型最頂端的啟動(dòng)類(lèi)加載器進(jìn)行加載努潘,因此Object類(lèi)在程序的各種類(lèi)加載器環(huán)境中都是同一個(gè)類(lèi)诽偷。

注意:如果自己定義的類(lèi)與rt.jar類(lèi)庫(kù)中類(lèi)重名【權(quán)限的類(lèi)名相同】,將會(huì)正常編譯疯坤,但是自己定義的類(lèi)將無(wú)法被加載運(yùn)行报慕。

雙親委派偽代碼

protected synchronized Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException {
  //首先,檢查請(qǐng)求的類(lèi)是否已經(jīng)被加載過(guò)了
  Class c = findLocalClass(name);
  if (null == c) {
    try {
      if (null != parent) {
        c = parent.loadClass(name, false);
      } else {
        c = findBootstrapClassOrNull(name);
      }
    } catch (ClassNotFoundException e) {
      //如果父類(lèi)加載器拋出異常压怠,說(shuō)明父類(lèi)加載器無(wú)法完成加載請(qǐng)求
    }
    if (null == c) {
      //父類(lèi)無(wú)法加載時(shí)眠冈,調(diào)用本身的findClass方法來(lái)進(jìn)行加載
      c = findClass(name);
    }
    if (resolve) {
      resolveClass(c);
    }
  }
  return c;
}

破壞雙親委派模型

問(wèn)題:雙親委派很好地解決了各個(gè)類(lèi)加載器的基礎(chǔ)類(lèi)的統(tǒng)一問(wèn)題【越基礎(chǔ)的類(lèi)由越上層加載器進(jìn)行加載】,但若基礎(chǔ)類(lèi)要回調(diào)用戶(hù)的代碼菌瘫,該怎么辦蜗顽?如:在JNDI服務(wù)中,它的代碼由啟動(dòng)類(lèi)加載器去加載雨让,但JNDI的目的是對(duì)資源進(jìn)行集中管理和查找雇盖,它需要調(diào)用由獨(dú)立廠商實(shí)現(xiàn)并部署在應(yīng)用程序的ClassPath下的JNDI接口提供者的代碼,但啟動(dòng)類(lèi)加載器不可能認(rèn)識(shí)這些代碼栖忠。
解答:Java提供了【線程上下文類(lèi)加載器】崔挖,通過(guò)setContextClassLoader()方法進(jìn)行設(shè)置,如果創(chuàng)建線程時(shí)沒(méi)有設(shè)置庵寞,將從父類(lèi)中繼承狸相,如果在應(yīng)用程序全局范圍內(nèi)都沒(méi)有設(shè)置的話,那這個(gè)類(lèi)加載器默認(rèn)是應(yīng)用程序類(lèi)加載器捐川。通過(guò)【線程上下文類(lèi)加載器】父類(lèi)加載器可以請(qǐng)求子類(lèi)加載器去完成類(lèi)加載的動(dòng)作卷哩。這種行為實(shí)際上就是通過(guò)了雙親委派模型的層次結(jié)構(gòu)來(lái)逆向使用類(lèi)加載器。

  • 動(dòng)態(tài)性追求導(dǎo)致雙親委派模型被破壞
    如:熱更新【Hot Swap】属拾、熱部署【Hot Deployment】
    模塊化熱部署的關(guān)鍵是它自定義的類(lèi)加載器機(jī)制的實(shí)現(xiàn)将谊,每一個(gè)程序模塊都有一個(gè)自己的類(lèi)加載器,當(dāng)需要更換一個(gè)Bundle時(shí)渐白,就把Bundle連同類(lèi)加載器一起更換以實(shí)現(xiàn)代碼的熱更新尊浓。

Tomcat中,JasperLoader的加載范圍僅僅是JSP文件所編譯出來(lái)的一個(gè)Class纯衍,它出現(xiàn)的目的就是被丟棄:當(dāng)服務(wù)器檢測(cè)到JSP文件被修改時(shí)栋齿,會(huì)替換掉目前的JasperLoader的實(shí)例,并通過(guò)再建立一個(gè)新的Jsp類(lèi)加載器來(lái)實(shí)現(xiàn)JSP文件的HotSwap功能。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瓦堵,一起剝皮案震驚了整個(gè)濱河市基协,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌菇用,老刑警劉巖澜驮,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異惋鸥,居然都是意外死亡杂穷,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)卦绣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)耐量,“玉大人,你說(shuō)我怎么就攤上這事滤港±妊眩” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵溅漾,是天一觀的道長(zhǎng)山叮。 經(jīng)常有香客問(wèn)我,道長(zhǎng)樟凄,這世上最難降的妖魔是什么聘芜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任兄渺,我火速辦了婚禮缝龄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挂谍。我一直安慰自己叔壤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布口叙。 她就那樣靜靜地躺著炼绘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪妄田。 梳的紋絲不亂的頭發(fā)上俺亮,一...
    開(kāi)封第一講書(shū)人閱讀 49,792評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音疟呐,去河邊找鬼脚曾。 笑死,一個(gè)胖子當(dāng)著我的面吹牛启具,可吹牛的內(nèi)容都是我干的本讥。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼拷沸!你這毒婦竟也來(lái)了色查?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤撞芍,失蹤者是張志新(化名)和其女友劉穎秧了,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體勤庐,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡示惊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了愉镰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片米罚。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖丈探,靈堂內(nèi)的尸體忽然破棺而出录择,到底是詐尸還是另有隱情,我是刑警寧澤碗降,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布隘竭,位于F島的核電站,受9級(jí)特大地震影響讼渊,放射性物質(zhì)發(fā)生泄漏动看。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一爪幻、第九天 我趴在偏房一處隱蔽的房頂上張望菱皆。 院中可真熱鬧,春花似錦挨稿、人聲如沸仇轻。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)篷店。三九已至,卻和暖如春臭家,著一層夾襖步出監(jiān)牢的瞬間疲陕,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工钉赁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蹄殃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓橄霉,卻偏偏與公主長(zhǎng)得像窃爷,于是被迫代替她去往敵國(guó)和親邑蒋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348