亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Tomcat源碼分析(八)--載入器

系統(tǒng) 2477 0
本系列轉(zhuǎn)載自?http://blog.csdn.net/haitao111313/article/category/1179996? ?

在講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方法:

  1. protected ?Class<?>?findClass(String?name)? throws ?ClassNotFoundException?{???
  2. ???????? byte []?classData?=?getClassData(name);? //getClassData方法是通過class文件的名字得到一個(gè)字節(jié)數(shù)組 ??
  3. ???????? if ?(classData?==? null )?{???
  4. ???????????? throw ? new ?ClassNotFoundException();???
  5. ????????}???
  6. ???????? else ?{???
  7. ???????????? return ?defineClass(name,?classData,? 0 ,?classData.length);? //加載進(jìn)jvm中。 ??
  8. ????????}???
  9. ????}???


問題是: 可不可以重寫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ī)制的:

  1. protected ? synchronized ?Class<?>?loadClass(String?name,? boolean ?resolve)??
  2. throws ?ClassNotFoundException??
  3. ???{??
  4. //?First,?check?if?the?class?has?already?been?loaded ??
  5. Class?c?=?findLoadedClass(name); //檢查該類是否已經(jīng)被加載了 ??
  6. if ?(c?==? null )?{??
  7. ???? try ?{??
  8. ???? if ?(parent?!=? null )?{ //如果父加載器不為空就用父加載器加載該類。 ??
  9. ????????c?=?parent.loadClass(name,? false );??
  10. ????}? else ?{??
  11. ????????c?=?findBootstrapClass0(name);??
  12. ????}??
  13. ????}? catch ?(ClassNotFoundException?e)?{??
  14. ???????? //?If?still?not?found,?then?invoke?findClass?in?order ??
  15. ???????? //?to?find?the?class. ??
  16. ????????c?=?findClass(name); //在自己實(shí)現(xiàn)的類加載器中重寫這個(gè)findClass方法。 ??
  17. ????}??
  18. }??
  19. if ?(resolve)?{??
  20. ????resolveClass(c);??
  21. }??
  22. return ?c;??
  23. ???}??
這樣就保證了父親委托機(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方法:

  1. private ?WebappClassLoader?createClassLoader()??
  2. ??????? throws ?Exception?{??
  3. ??
  4. ???????Class?clazz?=?Class.forName(loaderClass);??
  5. ???????WebappClassLoader?classLoader?=? null ;??
  6. ??
  7. ??????? if ?(parentClassLoader?==? null )?{??
  8. ??????????? //?Will?cause?a?ClassCast?is?the?class?does?not?extend?WCL,?but ??
  9. ??????????? //?this?is?on?purpose?(the?exception?will?be?caught?and?rethrown) ??
  10. ???????????classLoader?=?(WebappClassLoader)?clazz.newInstance();??
  11. ???????}? else ?{??
  12. ???????????Class[]?argTypes?=?{?ClassLoader. class ?};??
  13. ???????????Object[]?args?=?{?parentClassLoader?};??
  14. ???????????Constructor?constr?=?clazz.getConstructor(argTypes);??
  15. ???????????classLoader?=?(WebappClassLoader)?constr.newInstance(args);??
  16. ???????}??
  17. ??
  18. ??????? return ?classLoader;??
  19. ??
  20. ???}??

在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方法:

  1. public ?Class?loadClass(String?name,? boolean ?resolve)??
  2. ???????? throws ?ClassNotFoundException?{??
  3. ???????? if ?(debug?>=? 2 )??
  4. ????????????log( "loadClass(" ?+?name?+? ",?" ?+?resolve?+? ")" );??
  5. ????????Class?clazz?=? null ;??
  6. ??
  7. ???????? //?Don't?load?classes?if?class?loader?is?stopped ??
  8. ???????? if ?(!started)?{??
  9. ????????????log( "Lifecycle?error?:?CL?stopped" );??
  10. ???????????? throw ? new ?ClassNotFoundException(name);??
  11. ????????}??
  12. ??
  13. ???????? //?(0)?Check?our?previously?loaded?local?class?cache ??
  14. ???????? //查找本地緩存是否已經(jīng)加載了該類 ??
  15. ????????clazz?=?findLoadedClass0(name);??
  16. ???????? if ?(clazz?!=? null )?{??
  17. ???????????? if ?(debug?>=? 3 )??
  18. ????????????????log( "??Returning?class?from?cache" );??
  19. ???????????? if ?(resolve)??
  20. ????????????????resolveClass(clazz);??
  21. ???????????? return ?(clazz);??
  22. ????????}??
  23. ??
  24. ???????? //?(0.1)?Check?our?previously?loaded?class?cache ??
  25. ????????
  26. ????????clazz?=?findLoadedClass(name);??
  27. ???????? if ?(clazz?!=? null )?{??
  28. ???????????? if ?(debug?>=? 3 )??
  29. ????????????????log( "??Returning?class?from?cache" );??
  30. ???????????? if ?(resolve)??
  31. ????????????????resolveClass(clazz);??
  32. ???????????? return ?(clazz);??
  33. ????????}??
  34. ??
  35. ???????? //?(0.2)?Try?loading?the?class?with?the?system?class?loader,?to?prevent ??
  36. ???????? //???????the?webapp?from?overriding?J2SE?classes ??
  37. ???????? try ?{??
  38. ????????????clazz?=?system.loadClass(name); //?(0.2)?先檢查系統(tǒng)ClassLoader,因此WEB-INF/lib和WEB-INF/classes或{tomcat}/libs下的類定義不能覆蓋JVM?底層能夠查找到的定義(譬如不能通過定義java.lang.Integer替代底層的實(shí)現(xiàn) ??
  39. ???????????? if ?(clazz?!=? null )?{??
  40. ???????????????? if ?(resolve)??
  41. ????????????????????resolveClass(clazz);??
  42. ???????????????? return ?(clazz);??
  43. ????????????}??
  44. ????????}? catch ?(ClassNotFoundException?e)?{??
  45. ???????????? //?Ignore ??
  46. ????????}??
  47. ??
  48. ???????...............................................??
  49. //這是一個(gè)很奇怪的定義,JVM的ClassLoader建議先由parent去load,load不到自己再去load(見如上?ClassLoader部分),而Servelet規(guī)范的建議則恰好相反,Tomcat的實(shí)現(xiàn)則做個(gè)折中,由用戶去決定(context的?delegate定義),默認(rèn)使用Servlet規(guī)范的建議,即delegate=false ??
  50. ???????? boolean ?delegateLoad?=?delegate?||?filter(name);??
  51. //?(1)?先由parent去嘗試加載,此處的parent是SharedClassLoader,見如上說明,如上說明,除非設(shè)置了delegate,否則這里不執(zhí)行 ??
  52. ???????? //?(1)?Delegate?to?our?parent?if?requested ??
  53. ???????? if ?(delegateLoad)?{??
  54. ???????????? if ?(debug?>=? 3 )??
  55. ????????????????log( "??Delegating?to?parent?classloader" );??
  56. ????????????ClassLoader?loader?=?parent;??
  57. ???????????? if ?(loader?==? null ) //此處parent是否為空取決于context?的privileged屬性配置,默認(rèn)privileged=true,即parent為SharedClassLoader ??
  58. ????????????????loader?=?system;??
  59. ???????????? try ?{??
  60. ????????????????clazz?=?loader.loadClass(name);??
  61. ???????????????? if ?(clazz?!=? null )?{??
  62. ???????????????????? if ?(debug?>=? 3 )??
  63. ????????????????????????log( "??Loading?class?from?parent" );??
  64. ???????????????????? if ?(resolve)??
  65. ????????????????????????resolveClass(clazz);??
  66. ???????????????????? return ?(clazz);??
  67. ????????????????}??
  68. ????????????}? catch ?(ClassNotFoundException?e)?{??
  69. ????????????????;??
  70. ????????????}??
  71. ????????}??
  72. ??
  73. ??????? //?到WEB-INF/lib和WEB-INF/classes目錄去搜索,細(xì)節(jié)部分可以再看一下findClass,會(huì)發(fā)現(xiàn)默認(rèn)是先搜索WEB-INF/classes后搜索WEB-INF/lib ??
  74. ???????? if ?(debug?>=? 3 )??
  75. ????????????log( "??Searching?local?repositories" );??
  76. ???????? try ?{??
  77. ????????????clazz?=?findClass(name);??
  78. ???????????? if ?(clazz?!=? null )?{??
  79. ???????????????? if ?(debug?>=? 3 )??
  80. ????????????????????log( "??Loading?class?from?local?repository" );??
  81. ???????????????? if ?(resolve)??
  82. ????????????????????resolveClass(clazz);??
  83. ???????????????? return ?(clazz);??
  84. ????????????}??
  85. ????????}? catch ?(ClassNotFoundException?e)?{??
  86. ????????????;??
  87. ????????}??
  88. ??
  89. ???????? //?(3)?Delegate?to?parent?unconditionally ??
  90. ???????? if ?(!delegateLoad)?{??
  91. ???????????? if ?(debug?>=? 3 )??
  92. ????????????????log( "??Delegating?to?parent?classloader" );??
  93. ????????????ClassLoader?loader?=?parent;??
  94. ???????????? if ?(loader?==? null )??
  95. ????????????????loader?=?system;??
  96. ???????????? try ?{??
  97. ????????????????clazz?=?loader.loadClass(name);??
  98. ???????????????? if ?(clazz?!=? null )?{??
  99. ???????????????????? if ?(debug?>=? 3 )??
  100. ????????????????????????log( "??Loading?class?from?parent" );??
  101. ???????????????????? if ?(resolve)??
  102. ????????????????????????resolveClass(clazz);??
  103. ???????????????????? return ?(clazz);??
  104. ????????????????}??
  105. ????????????}? catch ?(ClassNotFoundException?e)?{??
  106. ????????????????;??
  107. ????????????}??
  108. ????????}??
  109. ??
  110. ???????? //?This?class?was?not?found ??
  111. ???????? throw ? new ?ClassNotFoundException(name);??
  112. ??
  113. ????}??

上面的代碼很長(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 這篇博文.

Tomcat源碼分析(八)--載入器


更多文章、技術(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ì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 国产精品久久久久久久成人午夜 | 免费在线中文字幕 | 激情影院免费看 | 亚洲精品第一综合99久久 | 青草视频网址 | 四虎免费入口 | aaa一级最新毛片 | 国产一级黄色录像 | 久久伊人精品综合观看99 | 91精品国产美女福到在线不卡 | 四虎在线观看免费永久 | 亚洲高清免费视频 | 国产一级毛片国产 | 曰本一级毛片免费播放 | 国产一区二区精品在线观看 | 天天摸夜夜添久久精品麻豆 | 欧美操操操操 | 99热久久国产精品这里小说 | 国产成人99精品免费观看 | 国产三级在线精品男人的天堂 | 97色综合| 免费一级特黄3大片视频 | 羞羞在线 | 亚洲精品在线播放视频 | 夜夜操操 | 亚洲日本中文字幕在线 | 伊人精品视频 | 亚洲另类伦春色综合妖色成人网 | 日本精品视频网站 | 国产欧美综合在线一区二区三区 | 99热最新网址获取 | 久久精品六 | 日本三级带日本三级带黄首页 | 日韩在线视频中文字幕 | 老湿机永久体验 | 欧美乱子伦一区二区三区 | 人人澡人人人人夜夜爽 | 国产精品久久久久久久久久98 | 日韩中文在线 | 一区二区在线播放福利视频 | 免费国产视频在线观看 |