簡聊Tomcat的類加載器架構

主流的Java Web服務器(也就是Web容器),如Tomcat淑趾、Jetty阳仔、WebLogic、WebSphere或其他筆者沒有列舉的服務器扣泊,都實現(xiàn)了自己定義的類加載器(一般都不止一個)近范。因為一個功能健全的Web容器嘶摊,要解決如下幾個問題:

  1)部署在同一個Web容器上的兩個Web應用程序所使用的Java類庫可以實現(xiàn)相互隔離。這是最基本的需求评矩,兩個不同的應用程序可能會依賴同一個第三方類庫的不同版本叶堆,不能要求一個類庫在一個服務器中只有一份,服務器應當保證兩個應用程序的類庫可以互相獨立使用斥杜。

  2)部署在同一個Web容器上的兩個Web應用程序所使用的Java類庫可以互相共享虱颗。這個需求也很常見,例如蔗喂,用戶可能有10個使用Spring組織的應用程序部署在同一臺服務器上忘渔,如果把10份Spring分別存放在各個應用程序的隔離目錄中,將會是很大的資源浪費——這主要倒不是浪費磁盤空間的問題弱恒,而是指類庫在使用時都要被加載到Web容器的內存辨萍,如果類庫不能共享,虛擬機的方法區(qū)就會很容易出現(xiàn)過度膨脹的風險返弹。

  3)Web容器需要盡可能地保證自身的安全不受部署的Web應用程序影響锈玉。目前,有許多主流的Java Web容器自身也是使用Java語言來實現(xiàn)的义起。因此拉背,Web容器本身也有類庫依賴的問題,一般來說默终,基于安全考慮椅棺,容器所使用的類庫應該與應用程序的類庫互相獨立。

  4)支持JSP應用的Web容器齐蔽,大多數(shù)都需要支持HotSwap功能两疚。我們知道,JSP文件最終要編譯成Java Class才能由虛擬機執(zhí)行含滴,但JSP文件由于其純文本存儲的特性诱渤,運行時修改的概率遠遠大于第三方類庫或程序自身的Class文件。而且ASP谈况、PHP和JSP這些網頁應用也把修改后無須重啟作為一個很大的“優(yōu)勢”來看待勺美,因此“主流”的Web容器都會支持JSP生成類的熱替換,當然也有“非主流”的碑韵,如運行在生產模式(Production Mode)下的WebLogic服務器默認就不會處理JSP文件的變化赡茸。

  由于存在上述問題,在部署Web應用時祝闻,單獨的一個Class Path就無法滿足需求了占卧,所以各種Web容都“不約而同”地提供了好幾個Class Path路徑供用戶存放第三方類庫,這些路徑一般都以“l(fā)ib”或“classes”命名。被放置到不同路徑中的類庫华蜒,具備不同的訪問范圍和服務對象舷蒲,通常,每一個目錄都會有一個相應的自定義類加載器去加載放置在里面的Java類庫∮讯啵現(xiàn)在牲平,就以Tomcat容器為例,看一看Tomcat具體是如何規(guī)劃用戶類庫結構和類加載器的域滥。

  在Tomcat目錄結構中纵柿,有3組目錄(“/common/*”、“/server/*”和“/shared/*”)可以存放Java類庫启绰,另外還可以加上Web應用程序自身的目錄“/WEB-INF/*”昂儒,一共4組,把Java類庫放置在這些目錄中的含義分別如下:

  ①放置在/common目錄中:類庫可被Tomcat和所有的Web應用程序共同使用委可。

  ②放置在/server目錄中:類庫可被Tomcat使用渊跋,對所有的Web應用程序都不可見。

  ③放置在/shared目錄中:類庫可被所有的Web應用程序共同使用着倾,但對Tomcat自己不可見拾酝。

  ④放置在/WebApp/WEB-INF目錄中:類庫僅僅可以被此Web應用程序使用,對Tomcat和其他Web應用程序都不可見卡者。

  為了支持這套目錄結構蒿囤,并對目錄里面的類庫進行加載和隔離,Tomcat自定義了多個類加載器崇决,這些類加載器按照經典的雙親委派模型來實現(xiàn)材诽,其關系如下圖所示。
image.png
  上圖中灰色背景的3個類加載器是JDK默認提供的類加載器恒傻,這3個加載器的作用已經介紹過了脸侥。而CommonClassLoader、CatalinaClassLoader盈厘、SharedClassLoader和WebappClassLoader則是Tomcat自己定義的類加載器睁枕,它們分別加載/common/*、/server/*扑庞、/shared/*和/WebApp/WEB-INF/*中的Java類庫譬重。其中WebApp類加載器和Jsp類加載器通常會存在多個實例拒逮,每一個Web應用程序對應一個WebApp類加載器罐氨,每一個JSP文件對應一個Jsp類加載器。

從圖中的委派關系中可以看出滩援,CommonClassLoader能加載的類都可以被Catalina ClassLoader和SharedClassLoader使用栅隐,而CatalinaClassLoader和Shared ClassLoader自己能加載的類則與對方相互隔離。WebAppClassLoader可以使用SharedClassLoader加載到的類,但各個WebAppClassLoader實例之間相互隔離租悄。而JasperLoader的加載范圍僅僅是這個JSP文件所編譯出來的那一個.Class文件谨究,它出現(xiàn)的目的就是為了被丟棄:當Web容器檢測到JSP文件被修改時,會替換掉目前的JasperLoader的實例泣棋,并通過再建立一個新的Jsp類加載器來實現(xiàn)JSP文件的HotSwap功能胶哲。

  對于Tomcat的6.x版本,只有指定了tomcat/conf/catalina.properties配置文件的server.loader和share.loader項后才會真正建立Catalina ClassLoader和Shared ClassLoader的實例潭辈,否則在用到這兩個類加載器的地方都會用Common ClassLoader的實例代替鸯屿,而默認的配置文件中沒有設置這兩個loader項,所以Tomcat 6.x順理成章地把/common把敢、/server和/shared三個目錄默認合并到一起變成一個/lib目錄寄摆,這個目錄里的類庫相當于以前/common目錄中類庫的作用。這是Tomcat設計團隊為了簡化大多數(shù)的部署場景所做的一項改進修赞,如果默認設置不能滿足需要婶恼,用戶可以通過修改配置文件指定server.loader和share.loader的方式重新啟用Tomcat 5.x的加載器架構。

  Tomcat加載器的實現(xiàn)清晰易懂柏副,并且采用了官方推薦的“正統(tǒng)”的使用類加載器的方式勾邦。如果讀者閱讀完上面的案例后,能完全理解Tomcat設計團隊這樣布置加載器架構的用意割择,那說明已經大致掌握了類加載器“主流”的使用方式检痰,那么筆者不妨再提一個問題讓讀者思考一下:前面曾經提到過一個場景,如果有10個Web應用程序都是用Spring來進行組織和管理的話锨推,可以把Spring放到Common或Shared目錄下讓這些程序共享铅歼。Spring要對用戶程序的類進行管理,自然要能訪問到用戶程序的類换可,而用戶的程序顯然是放在/WebApp/WEB-INF目錄中的椎椰,那么被CommonClassLoader或SharedClassLoader加載的Spring如何訪問并不在其加載范圍內的用戶程序呢?如果研究過虛擬機類加載器機制中的雙親委派模型沾鳄,相信讀者可以很容易地回答這個問題慨飘。

  分析:如果按主流的雙親委派機制,顯然無法做到讓父類加載器加載的類去訪問子類加載器加載的類译荞,上面在類加載器一節(jié)中提到過通過線程上下文方式傳播類加載器瓤的。

  答案是使用線程上下文類加載器來實現(xiàn)的,使用線程上下文加載器吞歼,可以讓父類加載器請求子類加載器去完成類加載的動作圈膏。看spring源碼發(fā)現(xiàn)篙骡,spring加載類所用的Classloader是通過Thread.currentThread().getContextClassLoader()來獲取的稽坤,而當線程創(chuàng)建時會默認setContextClassLoader(AppClassLoader)丈甸,即線程上下文類加載器被設置為AppClassLoader,spring中始終可以獲取到這個AppClassLoader(在Tomcat里就是WebAppClassLoader)子類加載器來加載bean尿褪,以后任何一個線程都可以通過getContextClassLoader()獲取到WebAppClassLoader來getbean了睦擂。
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市杖玲,隨后出現(xiàn)的幾起案子顿仇,更是在濱河造成了極大的恐慌,老刑警劉巖摆马,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夺欲,死亡現(xiàn)場離奇詭異,居然都是意外死亡今膊,警方通過查閱死者的電腦和手機些阅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斑唬,“玉大人市埋,你說我怎么就攤上這事∷×酰” “怎么了缤谎?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長褐着。 經常有香客問我坷澡,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮司顿,結果婚禮上,老公的妹妹穿的比我還像新娘斟赚。我一直安慰自己,他們只是感情好差油,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布拗军。 她就那樣靜靜地躺著,像睡著了一般蓄喇。 火紅的嫁衣襯著肌膚如雪发侵。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天妆偏,我揣著相機與錄音刃鳄,去河邊找鬼。 笑死楼眷,一個胖子當著我的面吹牛铲汪,可吹牛的內容都是我干的。 我是一名探鬼主播罐柳,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼掌腰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了张吉?” 一聲冷哼從身側響起齿梁,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肮蛹,沒想到半個月后勺择,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡伦忠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年省核,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片昆码。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡气忠,死狀恐怖,靈堂內的尸體忽然破棺而出赋咽,到底是詐尸還是另有隱情旧噪,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布脓匿,位于F島的核電站淘钟,受9級特大地震影響,放射性物質發(fā)生泄漏陪毡。R本人自食惡果不足惜米母,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望毡琉。 院中可真熱鬧爱咬,春花似錦、人聲如沸绊起。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽虱歪。三九已至蜂绎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間笋鄙,已是汗流浹背师枣。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留萧落,地道東北人践美。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓洗贰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親陨倡。 傳聞我的和親對象是個殘疾皇子敛滋,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內容