zyskm用夢想丈量人生,用奔跑丈量激情

          導航

          <2011年12月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          統計

          公告

          zyskm,zys是鄭勇勝的拼音簡寫,km公里的意思。
          以前曾跑過一段時間馬拉松,知道了這句名言“用夢想丈量人生,用奔跑丈量激情”,丈量的單位用公里km。

          常用鏈接

          留言簿(1)

          隨筆檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          tomcat類加載器及jar包沖突問題分析

          開發過程中遇到過這樣一個情況,在本地tomcat下開發調試正常,打包到測試環境的jboss下所有頁面都變成空白頁。
          項目日志和jboss日志沒有一點異常信息,費了半天勁把jboss所有日志全部打出來,發現是el.jar這個包里有空指針調用。
          檢查一下,項目WEB-INF\lib里有這個包呀,那應該是跟什么地方的jar包版本沖突了猜想,繼續找,在jboss-4.0.5.GA\server\default\lib下找到了對應包,比較了一下版本果然版本不一樣。
          把項目下的el-api.jar,jsp-api.jar,servlet-api.jar刪除,重新啟動,問題解決。
          接著有同事提出,同樣在tomcat下開發也出現這種情況,經檢查是他本地tomcat版本跟大家的不一致。開發環境這地方沒做到很好的統一。

          這樣問題是解決了,但是有一點就想不明白了,按照java的類加載委托機制,推測應該是先從jboss-4.0.5.GA\server\default\lib加載,如果加載不到的話再用當前類加載器加載WEB-INF\lib下的jar包,所有如果jboss下有jar包WEB-INF\lib下的應該不起作用,也有不會有沖突了。
          難到情況不是這樣的?

          一直想著找tomcat源碼分析一下來著,拖了好久。趕上這兩天不忙,就把apache-tomcat-6.0.33-src源文件弄了一份,debug看看到底怎樣。
          tomcat的類加載器結構和其他java項目是一致的。見圖一


          圖一
          其類圖見圖二

          圖二
          elipse debug截圖倒過來看跟這個就一樣了。
          Tomcat 通過Lifecycle接口來實現容器生命周期的統一管理,跟類加載器關系不大,這里就不討論了。
          通過這樣大容器啟動的時候啟動子容器,逐級加載。其結構關系跟server.xml描述的基本一致,詳細可以參考我的上一篇文章

          Tomcat6結構分析
          http://www.aygfsteel.com/zyskm/archive/2011/10/24/361870.html

          (這個編輯工具不太會用,樣式難看點,湊合看了)
          每個容器都有自己的類加載器,在默認情況下都是StandardClassLoader的實例。
          委托機制也和標準的java實現沒什么兩樣。

          接著往下看項目對應的類加載
          StandardContext.start();調用WebappLoader.start()開始加載項目,WebappLoader又通過創建一個WebappClassLoader實例進行類加載。
          WebappClassLoader.loadClass()實現依然波瀾不驚,規規矩矩的先從緩存找,找不到調用findClass()進行加載。
          果然這里實現有點不同,是先自己找,找不到再委托上級查找。和java默認的加載方式不同。
          見源代碼,只留下原理部分,日志和調試信息都去掉了。

          public Class findClass(String name) throws ClassNotFoundException {
                  
          // 先自己加載類,找不到則請求parent來加載,注意這點和java默認的委托模式不同
                  Class clazz = null;
                  
          try {
                      
          if ((clazz == null)) {
                              clazz 
          = findClassInternal(name);
                      }

                      
          if ((clazz == null&& hasExternalRepositories && !searchExternalFirst) {
                              clazz 
          = super.findClass(name);
                      }

                      
          if (clazz == null{
                          
          throw new ClassNotFoundException(name);
                      }

                  }
           catch (ClassNotFoundException e) {
                      
          if (log.isTraceEnabled())
                          log.trace(
          "    --> Passing on ClassNotFoundException");
                      
          throw e;
                  }

                  
          return (clazz);
          }

          據此可以認為,在web項目WEB-INF\lib下的jar包優先級高于jboss,tomcat 下的lib.
          兩處版本不一致的話會導致程序異常。
          比較省事的辦法是WEB-INF\lib下不再保留重復的jar包,實在閑著沒事的話可以自己寫個類加載器替換tomcat下WebappClassLoader改變加載順序。
          但是還可能有隱患,WebappClassLoader權限較低,它加載的類只能訪問web應用下的資源,如果servlet-api.jar等包用到其他資源時可能出現異常。
          這個沒實際測過,只是推測。但是catalina要提供對整個容器的支持,servlet-api實現對http協議的封裝轉換用到外部資源的可能性很大。


          圖三 類加載器結構圖

          總結:
          sevlet-api.jar,jsp-api.jar,el-api.jar這類容器提供的jar包web項目下沒必要再保留一份了,容易出現版本不一致。

          附錄:
          查看tomcat源碼的時候可以看看how tomcat works這本書,很不錯,雖然老了點。

          作者:zyskm
          http://www.aygfsteel.com/zyskm

          posted on 2011-12-06 13:43 zyskm 閱讀(10727) 評論(3)  編輯  收藏

          評論

          # re: tomcat類加載器及jar包沖突問題分析 2011-12-07 08:49 tb

          講得不錯 學習了   回復  更多評論   

          # re: tomcat類加載器及jar包沖突問題分析 2011-12-07 17:07 雪地靴

          linux的就是強大。  回復  更多評論   

          # re: tomcat類加載器及jar包沖突問題分析 2011-12-08 15:12 zyskm

          這內容跟linux沒啥關系呀@雪地靴
            回復  更多評論   


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 太仆寺旗| 莆田市| 通海县| 永修县| 鹤壁市| 密山市| 洛隆县| 抚松县| 叙永县| 达拉特旗| 汾西县| 吴川市| 巴青县| 滦平县| 达州市| 赤水市| 双江| 固安县| 运城市| 原阳县| 井冈山市| 珠海市| 峡江县| 南京市| 大埔区| 冷水江市| 宜兴市| 屏东县| 峨眉山市| 禹州市| 涟水县| 边坝县| 信宜市| 敦煌市| 潮安县| 施秉县| 藁城市| 云梦县| 巴南区| 尖扎县| 罗城|