在講Tomcat的載入器之前,先要了解一下java的類加載機(jī)制,這里就不具體說了,僅僅寫一點(diǎn)我認(rèn)為比較重要的東西:
? ? 1:一般實(shí)現(xiàn)自己的類加載器是重寫ClassLoader的findClass方法,然后在這個(gè)方法里面讀取class文件為byte[]數(shù)組,傳入defineClass方法,defineClass方法返回我們加載的類。這樣便實(shí)現(xiàn)了我們自己的簡(jiǎn)單的類加載器。下面是一個(gè)簡(jiǎn)單的自定義類加載器的findClass方法:
問題是: 可不可以重寫ClassLoader的loadClass方法來實(shí)現(xiàn)自己的類加載器? 答案是可以,Tomcat就是用的這種方法。jdk建議我們實(shí)現(xiàn)自己的類加載器的時(shí)候是重寫findClass方法,不建議重寫loadclass方法,因?yàn)镃lassLoader的loadclass方法保證了類加載的父親委托機(jī)制,如果重寫了這個(gè)方法,就意味著需要實(shí)現(xiàn)自己在重寫的loadclass方法實(shí)現(xiàn)父親委托機(jī)制,下面看看ClassLoader的loadclass方法,看怎么實(shí)現(xiàn)父親委托機(jī)制的:
這樣就保證了父親委托機(jī)制。當(dāng)所有父類都加載不了,才會(huì)調(diào)用findClass方法,即調(diào)用到我們自己的類加載器的findClass方法。以此實(shí)現(xiàn)類加載。
2:在我們自己實(shí)現(xiàn)的類加載器中,defineClass方法才是真正的把類加載進(jìn)jvm,defineClass是從ClassLoader繼承而來,把一個(gè)表示類的字節(jié)數(shù)組加載進(jìn)jvm轉(zhuǎn)換為一個(gè)類。
3:我們自己實(shí)現(xiàn)的類加載器跟系統(tǒng)的類加載器沒有本質(zhì)的區(qū)別,最大的區(qū)別就是加載的路徑不同,系統(tǒng)類加載器會(huì)加載環(huán)境變量CLASSPATH中指明的路徑和jvr文件,我們自己的類加載器可以定義自己的需要加載的類文件路徑.同樣的一個(gè)class文件,用系統(tǒng)類加載器和自定義加載器加載進(jìn)jvm后類的結(jié)構(gòu)是沒有區(qū)別的,只是他們?cè)L問的權(quán)限不一樣,生成的對(duì)象因?yàn)榧虞d器不同也會(huì)不一樣.當(dāng)然我們自己的類加載器可以有更大的靈活性,比如把一個(gè)class文件(其實(shí)就是二進(jìn)制文件)加密后(簡(jiǎn)單的加密就把0和1互換),系統(tǒng)類加載器就不能加載,需要由我們自己定義解密類的加載器才能加載該class文件.
現(xiàn)在來初步的看看Tomcat的類加載器,為什么Tomcat要有自己的類加載器.這么說吧,假如沒有自己的類加載器,我們知道,在一個(gè)Tomcat中是可以部署很多應(yīng)用的,如果所有的類都由系統(tǒng)類加載器來加載,那么部署在Tomcat上的A應(yīng)用就可以訪問B應(yīng)用的類,這樣A應(yīng)用與B應(yīng)用之間就沒有安全性可言了。還有一個(gè)原因是因?yàn)門omcat需要實(shí)現(xiàn)類的自動(dòng)重載,所以也需要實(shí)現(xiàn)自己的類加載器。Tomcat的載入器是實(shí)現(xiàn)了Loader接口的WebappLoader類,也是Tomcat的一個(gè)組件,實(shí)現(xiàn)Lifecycle接口以便統(tǒng)一管理,啟動(dòng)時(shí)調(diào)用start方法,在start方法主要做了以下的事情:
1:創(chuàng)建一個(gè)真正的類加載器以及設(shè)置它加載的路徑,調(diào)用createClassLoader方法
2:?jiǎn)?dòng)一個(gè)線程來支持自動(dòng)重載,調(diào)用threadStart方法
看createClassLoader方法:
在createClassLoader方法內(nèi),實(shí)例化了一個(gè)真正的類加載器WebappClassLoader,代碼很簡(jiǎn)單。WebappClassLoader是Tomcat的類加載器,它繼承了URLClassLoader(這個(gè)類是ClassLoader的孫子類)類。重寫了findClass和loadClass方法。Tomcat的findClass方法并沒有加載相關(guān)的類,只是從已經(jīng)加載的類中查找這個(gè)類有沒有被加載,具體的加載是在重寫的loadClass方法中實(shí)現(xiàn),從上面的對(duì)java的討論可知,重寫了loadClass方法就意味著失去了類加載器的父親委托機(jī)制,需要自己來實(shí)現(xiàn)父親委托機(jī)制。Tomcat正是這么做的,下面看WebappClassLoader的loadClass方法:
上面的代碼很長(zhǎng),但實(shí)現(xiàn)了Tomcat自己的類加載機(jī)制,具體的加載規(guī)則是:
1:因?yàn)樗幸呀?jīng)載入的類都會(huì)緩存起來,所以先檢查本地緩存
2:如本地緩存沒有,則檢查上一級(jí)緩存,即調(diào)用ClassLoader類的findLoadedClass()方法;
3:若兩個(gè)緩存都沒有,則使用系統(tǒng)的類進(jìn)行加載,防止Web應(yīng)用程序中的類覆蓋J2EE的類
4:若打開標(biāo)志位delegate(表示是否代理給父加載器加載),或者待載入的類是屬于包觸發(fā)器的包名,則調(diào)用父類載入器來加載,如果父類載入器是null,則使用系統(tǒng)類載入器
5:從當(dāng)前倉(cāng)庫(kù)中載入相關(guān)類
6:若當(dāng)前倉(cāng)庫(kù)中沒有相關(guān)類,且標(biāo)志位delegate為false,則調(diào)用父類載入器來加載,如果父類載入器是null,則使用系統(tǒng)類載入器(4跟6只能執(zhí)行一個(gè)步驟的)
這里有有一點(diǎn)不明白的是在第三步使用系統(tǒng)類加載若失敗后,在第四步和第六步就沒必要但父類載入器為null的時(shí)候再用系統(tǒng)類載入器來載入了???有誰明白的麻煩留個(gè)言,不勝感激~
參考了一下 http://ayufox.iteye.com/blog/631190 這篇博文.
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
