<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    放翁(文初)的一畝三分地

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      210 隨筆 :: 1 文章 :: 320 評論 :: 0 Trackbacks
     

           工作忙,有些許時間沒有更新Blog了,這次在開發(fā)監(jiān)控模塊的時候遇到了這個問題,整個問題定位過程真是走了不少路,所以覺得有必要記錄下來分享一下。在我看來很多時候結(jié)果也許就很簡單一個原因,但是開發(fā)人員卻要探究很久,也許在找到了其他可實現(xiàn)業(yè)務(wù)邏輯方法的情況下,就會放棄尋找原因,這期間我也是一樣。

    問題初現(xiàn):

           在服務(wù)集成平臺中需要新增一塊寫入數(shù)據(jù)庫的邏輯,因此考慮最簡便就是弄個SpringBeanFactory來搞定這一切,誰知道,問題就這么出現(xiàn)了。很簡單,通過SpringClassPathXmlApplicationContext來構(gòu)建BeanFactory,下面的語句大家應(yīng)該很熟悉:

    ctx = new ClassPathXmlApplicationContext("/spring/sip-*.xml");

           通過通配符來載入ClassPath下的所有的符合規(guī)則的spring配置文件。然后在Eclipse中作完單元測試和集成測試,一切正常。然后用我們內(nèi)部的打包部署,而這些配置文件都被打在Jar中作為lib庫依賴。結(jié)果啟動以后,在分析完日志需要寫入到數(shù)據(jù)庫的時候出現(xiàn)異常:

    Could not resolve bean definition resource pattern [/spring/sip-*.xml]; nested exception is java.io.FileNotFoundException: class path resource [spring/] cannot be resolved to URL because it does not exist

    就提示來說,就是沒有找到spring這個目錄,也就是在ClassPath下面就沒有找到資源。

    第一次試圖解決問題:

    以前調(diào)整過Jboss關(guān)于ClassLoader的配置,即自上而下搜索還是自下而上搜索,以及是否采用Web容器的ClassLoader,開始懷疑是否是這種修改造成的問題。修改了沒有問題,然后就設(shè)置斷點跟蹤SpringClassPathXmlApplicationContext的構(gòu)造過程,發(fā)現(xiàn)Spring在分析此類通配類型的過程中,首先將前面的文件目錄和后面的具體通配文件分開,先定位文件目錄資源,也就是在定位文件目錄資源的過程中,找不到spring目錄,而出現(xiàn)了那個異常。看了代碼中也有對Jar的處理,但是在處理之前就出現(xiàn)了問題。

    自己做了嘗試,將spring目錄和其內(nèi)容解壓到WebClasses目錄下運(yùn)行正常,或者解壓到war下面也是正常的,這些地方其實都是ClassPath可以找到的,但是lib目錄下的jar也應(yīng)該是可以找到的。在仔細(xì)跟蹤了代碼中最后載入這些資源的ClassLoader內(nèi)的數(shù)據(jù),所有的Jar都是包含在內(nèi)的。

    由于工作太多,因此將原有的打包模式作了修改,每次打包將這部分配置解壓到war下面,這樣就找到了可解決方案了,因此細(xì)致的緣由也就沒有再去追究。(如果不是后面再次遇到,這個問題就會在此了結(jié))

    問題再現(xiàn):

           監(jiān)控模塊中需要新增一塊寫入數(shù)據(jù)庫的邏輯,在單元測試和集成測試通過的情況下出現(xiàn)了問題,由于此次是普通的J2SE的應(yīng)用,所有的配置和依賴都打入在了Jar中,所以問題和前次一樣。

           這次決定花一些時間好好找到問題所在,首先覺的Spring的資源載入應(yīng)該不會不支持從Jar中載入,這是最基本的功能,因此再次打開了Spring的源碼。

    問題二次定位:

    先看看ClassPathXmlApplicationContext的類圖結(jié)構(gòu):




        關(guān)鍵方法就是getResource方法,ClassPathXmlApplicationContext的資源定位就是采用了DefaultResourceLoadergetResource方法。內(nèi)部也沒有做太多的工作,其實就是如下的代碼:

    try

    {

                          // Try to parse the location as a URL...

                          URL url = new URL(location);

                          returnnew UrlResource(url);

               }

               catch (MalformedURLException ex)

    {

                     // No URL -> resolve as resource path.

                     return getResourceByPath(location);

          }

    上面的代碼都是標(biāo)準(zhǔn)的j2se的代碼.作為URL通過字符串來構(gòu)造,通常需要能夠首先獲得URL的資源全路徑,而在當(dāng)前情況下發(fā)現(xiàn)到獲取資源的時候location還是保持了spring/的狀態(tài),而沒有被替換成為所在jar的資源全路徑,那么就先作以下測試:

        新建簡單的項目,然后在項目中加入包含spring配置的jar,然后作單元測試,測試代碼如下:

    URL url = Thread.currentThread().getClass().getResource("/spring/");

        未獲取到URL,出現(xiàn)異常。

    URL url = Thread.currentThread().getClass().getResource("/spring/sip-analyzer-dataSource.xml");

           正常獲取到了URL

    由此看來應(yīng)該是在獲取Jar中的目錄資源路徑的時候出現(xiàn)問題導(dǎo)致后續(xù)載入出現(xiàn)問題,嘗試直接傳入具體的文件名:

    ctx = new ClassPathXmlApplicationContext("/spring/sip-analyzer-dataSource.xml");

    發(fā)現(xiàn)還是出現(xiàn)問題,在new URL的時候傳入的是沒有翻譯過的文件名,考慮在傳入的過程中就直接替換成為資源路徑,因此寫了一個簡單的方法:

    publicstatic String[] getRealClassPath(String[] locationfile)

          {

               String[] result = locationfile;

                     for(int i = 0 ; i < locationfile.length; i++)

                     {

                          try

                          {

                                URL url = Thread.currentThread().getClass().getResource(locationfile[i]);

                                String file = url.getFile();

                                if (file.indexOf(".jar!") > 0)

                                      result[i] = new StringBuffer("jar:").append(file.substring(0,file.indexOf(".jar!")+".jar!".length()))

                                                 .append(locationfile[i]).toString();

                          }

                          catch(Exception ex)

                          {}

                     }

              

               returnresult;

    }

    在將構(gòu)造工廠類修改為:

    ctx = new ClassPathXmlApplicationContext(BaseUtil.getRealClassPath(new String[]{"/spring/sip-analyzer-dataSource.xml"}));

    運(yùn)行測試,正常啟動,這也就是又變成最原始的文件羅列的模式。問題雖然找到了解決方案,但是始終覺得很別扭,同時對于無法在Jar中載入配置資源的情況我一直都還是覺得應(yīng)該不是Spring的問題。

    峰回路轉(zhuǎn):

    晚上到家還是有點不死心,就直接建了個項目作單元測試,然后將一個自己建立的Jar加入到Classpath下面,作單元測試,結(jié)果大吃一驚。

    URL url = Thread.currentThread().getClass().getResource("/test/");

    URL url = Thread.currentThread().getClass().getResource("/test/test.txt");

    都正常獲取到了資源,這完全推翻了我早先認(rèn)為在Jar中無法獲得目錄作為資源的問題。然后把公司里面的項目重新打包然后加入到ClassPath下,驗證spring的目錄,出錯,目錄無法獲取,此時我確定看來應(yīng)該不是應(yīng)用的問題,而是環(huán)境問題。檢查了兩個Jar,看似沒有什么區(qū)別,將公司項目的Jar中的spring目錄拷貝到測試的jar中,然后作測試,可以找到目錄。那么問題完全定位到了Jar本身。通過RAR的壓縮工具看了一下兩個Jar的信息,除了顯示所謂的壓縮平臺不同(一個是DOS,一個是Unix)其他沒有任何區(qū)別。然后自己用RAR打了一個Jar以及在linux下打了一個Jar做了測試,兩個Jar內(nèi)的目錄都是正常可以被獲取。

    無意中我換了一下需要獲取的目錄名稱,也就是說在公司項目中有多個目錄在jar中,這次換成為ibatis目錄,正常獲取,看來不是Jar的格式。回想了一下,公司的打包工具是自己人寫的,其中提供了一個特性,如果一個項目內(nèi)部的一些配置信息是需要讓調(diào)用它的第三方在編譯期配置,那么可以通過在第三方項目構(gòu)建的過程中,動態(tài)的生成配置文件然后植入到被依賴的jar中。而spring這個目錄中由于那些數(shù)據(jù)庫的配置都是需要動態(tài)配置的,因此spring的那個目錄是后期被寫入的,而ibatis是早先就固化在項目中的。

    由于我們的JarMETA-INF中都有INDEX.LIST文件,過去遇到過在JAR中自己手工放入一些文件由于沒有修改INDEX.LIST而導(dǎo)致雖然文件已經(jīng)存在但是不會被發(fā)現(xiàn),于是打開公司項目中的Jar,果然INDEX.LIST中只有ibatis,而沒有spring,看來是我的同事在寫入的時候沒有將INDEX.LIST更新。立刻將INDEX.LIST作了更新,測試spring目錄,結(jié)果依然出錯。看來這還不是問題的根本。

    立刻問了我們開發(fā)打包工具的同事,向他們要寫入Jar的代碼,對方的回答是就是采用簡單的JarOutputStream來寫入,沒有什么特殊的。那我就開始懷疑是否是因為采用這種方式寫入到Jar中的目錄在被資源定位的時候會出現(xiàn)問題。于是寫了下面的代碼:

    JarOutputStream jos;

               try

               {

                     jos = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(file)));

                     String f = "spring/sip-analyzer-dataSource.xml";

                     File source = new File(f);

                     JarEntry je = new JarEntry(f);

                     jos.putNextEntry(je);

                     BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:/work/sip3/analyzer/src/conf.test/spring/sip-analyzer-dataSource.xml"));

                     int i = 0;

                     while ((i=bis.read())!=-1)

                     {

                          jos.write(i);

                     }

                     bis.close();

                     jos.closeEntry();

                     jos.close();

    } catch  ...

    結(jié)果創(chuàng)建出來的Jar中的spring目錄無法被資源定位,同樣在這個Jar中直接拖入一個目錄test,然后刷新測試,test目錄可以被定位。

    后續(xù)

           就到了這個階段來看如果以上面這種方式寫入,對于目錄資源定位的卻存在問題。這個問題還沒有最終的肯定的結(jié)論,在我現(xiàn)在所有的試驗來看,不論是否有INDEX.LIST,或者INDEX.LIST,如果用程序?qū)懭氲?/span>Jar中,目錄作為資源定位都會出現(xiàn)問題(起碼是上面那種普通寫入方式)。

           這種情況可能是由于這種寫法還有一些其他需要配置的,例如寫入到META-INF/INDEX.LIST中,或者就是J2SE現(xiàn)在API存在的一個問題。不過不管是什么問題,起碼值得引起重視,特別是現(xiàn)在類似于Spring框架載入Jar目錄下的配置。

    posted on 2008-05-28 16:42 岑文初 閱讀(3846) 評論(2)  編輯  收藏

    評論

    # re: Java 載入Jar內(nèi)資源問題的探究 2008-05-29 17:51 yeshucheng
    代碼字體太小,呵呵。希望以后調(diào)整下。整體不錯  回復(fù)  更多評論
      

    # re: Java 載入Jar內(nèi)資源問題的探究 2011-05-19 16:35 多福多壽
    額鵝鵝鵝鵝鵝鵝鵝鵝鵝鵝鵝鵝鵝鵝鵝  回復(fù)  更多評論
      


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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲综合图色40p| 久久亚洲国产最新网站| 精品久久8x国产免费观看| 亚洲综合av一区二区三区不卡| 免费中文字幕一级毛片| 在线观看免费无码视频| 亚洲一级毛片在线观| 亚洲精品天堂成人片?V在线播放| 日本一道本不卡免费| 亚洲成a人无码亚洲成av无码 | 暖暖在线日本免费中文| 成人无码视频97免费| 亚洲天堂2017无码中文| 国产亚洲AV手机在线观看| 国产成人免费爽爽爽视频| 久久免费精品视频| 久久久亚洲精华液精华液精华液| 亚洲VA成无码人在线观看天堂| 国产日产成人免费视频在线观看| 无码少妇精品一区二区免费动态 | 91av免费观看| xxxxx做受大片视频免费| 亚洲不卡1卡2卡三卡2021麻豆| 国产亚洲精品拍拍拍拍拍| 在线视频免费观看www动漫| 久9热免费精品视频在线观看| 看全免费的一级毛片| 67194在线午夜亚洲| 久久精品视频亚洲| 亚洲综合国产一区二区三区| 午夜神器成在线人成在线人免费 | 77777亚洲午夜久久多人| 岛国片在线免费观看| 中文字幕在线观看免费视频 | 亚洲精品国产第一综合99久久| 亚洲黄色在线观看视频| 亚洲AV永久纯肉无码精品动漫| 亚洲日韩涩涩成人午夜私人影院| 日韩在线看片免费人成视频播放| 91黑丝国产线观看免费| 一级毛片免费观看不卡的|