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

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

系統 2101 0
本系列轉載自?http://blog.csdn.net/haitao111313/article/category/1179996? ?

在講Tomcat的載入器之前,先要了解一下java的類加載機制,這里就不具體說了,僅僅寫一點我認為比較重要的東西:

? ? 1:一般實現自己的類加載器是重寫ClassLoader的findClass方法,然后在這個方法里面讀取class文件為byte[]數組,傳入defineClass方法,defineClass方法返回我們加載的類。這樣便實現了我們自己的簡單的類加載器。下面是一個簡單的自定義類加載器的findClass方法:

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


問題是: 可不可以重寫ClassLoader的loadClass方法來實現自己的類加載器? 答案是可以,Tomcat就是用的這種方法。jdk建議我們實現自己的類加載器的時候是重寫findClass方法,不建議重寫loadclass方法,因為ClassLoader的loadclass方法保證了類加載的父親委托機制,如果重寫了這個方法,就意味著需要實現自己在重寫的loadclass方法實現父親委托機制,下面看看ClassLoader的loadclass方法,看怎么實現父親委托機制的:

  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); //檢查該類是否已經被加載了 ??
  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); //在自己實現的類加載器中重寫這個findClass方法。 ??
  17. ????}??
  18. }??
  19. if ?(resolve)?{??
  20. ????resolveClass(c);??
  21. }??
  22. return ?c;??
  23. ???}??
這樣就保證了父親委托機制。當所有父類都加載不了,才會調用findClass方法,即調用到我們自己的類加載器的findClass方法。以此實現類加載。

2:在我們自己實現的類加載器中,defineClass方法才是真正的把類加載進jvm,defineClass是從ClassLoader繼承而來,把一個表示類的字節數組加載進jvm轉換為一個類。

3:我們自己實現的類加載器跟系統的類加載器沒有本質的區別,最大的區別就是加載的路徑不同,系統類加載器會加載環境變量CLASSPATH中指明的路徑和jvr文件,我們自己的類加載器可以定義自己的需要加載的類文件路徑.同樣的一個class文件,用系統類加載器和自定義加載器加載進jvm后類的結構是沒有區別的,只是他們訪問的權限不一樣,生成的對象因為加載器不同也會不一樣.當然我們自己的類加載器可以有更大的靈活性,比如把一個class文件(其實就是二進制文件)加密后(簡單的加密就把0和1互換),系統類加載器就不能加載,需要由我們自己定義解密類的加載器才能加載該class文件.

現在來初步的看看Tomcat的類加載器,為什么Tomcat要有自己的類加載器.這么說吧,假如沒有自己的類加載器,我們知道,在一個Tomcat中是可以部署很多應用的,如果所有的類都由系統類加載器來加載,那么部署在Tomcat上的A應用就可以訪問B應用的類,這樣A應用與B應用之間就沒有安全性可言了。還有一個原因是因為Tomcat需要實現類的自動重載,所以也需要實現自己的類加載器。Tomcat的載入器是實現了Loader接口的WebappLoader類,也是Tomcat的一個組件,實現Lifecycle接口以便統一管理,啟動時調用start方法,在start方法主要做了以下的事情:

1:創建一個真正的類加載器以及設置它加載的路徑,調用createClassLoader方法

2:啟動一個線程來支持自動重載,調用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方法內,實例化了一個真正的類加載器WebappClassLoader,代碼很簡單。WebappClassLoader是Tomcat的類加載器,它繼承了URLClassLoader(這個類是ClassLoader的孫子類)類。重寫了findClass和loadClass方法。Tomcat的findClass方法并沒有加載相關的類,只是從已經加載的類中查找這個類有沒有被加載,具體的加載是在重寫的loadClass方法中實現,從上面的對java的討論可知,重寫了loadClass方法就意味著失去了類加載器的父親委托機制,需要自己來實現父親委托機制。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. ???????? //查找本地緩存是否已經加載了該類 ??
  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)?先檢查系統ClassLoader,因此WEB-INF/lib和WEB-INF/classes或{tomcat}/libs下的類定義不能覆蓋JVM?底層能夠查找到的定義(譬如不能通過定義java.lang.Integer替代底層的實現 ??
  39. ???????????? if ?(clazz?!=? null )?{??
  40. ???????????????? if ?(resolve)??
  41. ????????????????????resolveClass(clazz);??
  42. ???????????????? return ?(clazz);??
  43. ????????????}??
  44. ????????}? catch ?(ClassNotFoundException?e)?{??
  45. ???????????? //?Ignore ??
  46. ????????}??
  47. ??
  48. ???????...............................................??
  49. //這是一個很奇怪的定義,JVM的ClassLoader建議先由parent去load,load不到自己再去load(見如上?ClassLoader部分),而Servelet規范的建議則恰好相反,Tomcat的實現則做個折中,由用戶去決定(context的?delegate定義),默認使用Servlet規范的建議,即delegate=false ??
  50. ???????? boolean ?delegateLoad?=?delegate?||?filter(name);??
  51. //?(1)?先由parent去嘗試加載,此處的parent是SharedClassLoader,見如上說明,如上說明,除非設置了delegate,否則這里不執行 ??
  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屬性配置,默認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目錄去搜索,細節部分可以再看一下findClass,會發現默認是先搜索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. ????}??

上面的代碼很長,但實現了Tomcat自己的類加載機制,具體的加載規則是:

1:因為所有已經載入的類都會緩存起來,所以先檢查本地緩存

2:如本地緩存沒有,則檢查上一級緩存,即調用ClassLoader類的findLoadedClass()方法;

3:若兩個緩存都沒有,則使用系統的類進行加載,防止Web應用程序中的類覆蓋J2EE的類

4:若打開標志位delegate(表示是否代理給父加載器加載),或者待載入的類是屬于包觸發器的包名,則調用父類載入器來加載,如果父類載入器是null,則使用系統類載入器

5:從當前倉庫中載入相關類

6:若當前倉庫中沒有相關類,且標志位delegate為false,則調用父類載入器來加載,如果父類載入器是null,則使用系統類載入器(4跟6只能執行一個步驟的)

這里有有一點不明白的是在第三步使用系統類加載若失敗后,在第四步和第六步就沒必要但父類載入器為null的時候再用系統類載入器來載入了???有誰明白的麻煩留個言,不勝感激~

參考了一下 http://ayufox.iteye.com/blog/631190 這篇博文.

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


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

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

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产啪视频1000部免费视频 | 日本黄页网址 | 四虎影视2022入口网址 | 狠狠操夜夜操 | 亚洲国产日产韩国欧美综合 | 91香蕉福利一区二区三区 | 毛片免费全部播放一级 | 亚洲一区二区三区在线免费观看 | 亚洲操穴 | 欧美jizzhd欧美巨大 | 欧美日韩亚洲国产一区二区综合 | 国产亚洲精品自在久久不卡 | 精品久久中文字幕 | 999热成人精品国产免 | 91香蕉黄| 久久91精品久久久久久水蜜桃 | 欧美伊人久久久久久久久影院 | 国内精品在线视频 | 国产精品福利一区二区 | www.五月天激情 | 国产成人教育视频在线观看 | 中文一级片 | 天天干天天操天天玩 | 毛片站 | 亚洲日本欧美在线 | 五月婷婷综合激情网 | 亚洲成在人线影视天堂网 | 亚洲色无码播放 | 男人资源在线观看 | 欧美视频 亚洲视频 | 天天摸天天爽天天澡视频 | 中文字幕中文字幕中中文 | 久久精品免费大片国产大片 | 午夜视频网址 | 国产福利一区二区三区在线视频 | 91精品久久久久久久久久 | 女人18毛片特级一级免费视频 | 国产精品久久久久久久久免费观看 | 另类婷婷 | 亚州精品一区二区三区 | 成人观看网站a |