這個問題其實一開始是在 Spring 上引發的,所以也可以列入 Spring 的類別中。


出於實驗性質,將工作上兩個專案合併,這兩個專案都以 Spring 為架構基礎,合併時將其中一個專案先包成 jar,由另一個專案所引用,然後修改此專案的 Spring 主配置檔,用 import tag 來引入包在 jar 檔內的其他 Spring 配置檔。因為 jar 檔內的 Spring 配置檔不少但檔名相同,所以使用了萬用字元的宣告方式,如:
    <import resource="classpath:/**/services.xml"/>
 
原本以為這樣一切沒問題,但在啟動完 Tomcat 後卻發現包在 jar 檔內的 Spring 配置檔全都沒被讀入。找了不少網路的文章都沒有解決方法,而 Spring 官方文件上更是說萬用字元可以用在 classpath 與 jar 檔上 (官方文件 4.7.2.1 節)。不得已之下只能去追 Spring 的 Source,一直追到最後發現 Spring 是用 ClassLoader 的 getSource() 去載入萬用字元 * 之前的路徑。
 
於是我自己寫了一個測試程式直接用 ClassLoader 的 getSource() 去載入位於 jar 檔內的 path,結果發現回傳真的是 null。看來問題並不在 Spring 身上,於是改變找尋問題的關鍵字,終於讓我找到這篇前人問過的問題「getResource(path) fails in jar」,請看第四格 Tom Blough 的回文,裏面提到說這個問題是因為 path 並不存在於 jar 檔中 (because the path itself did not exist in the jar)。同一格回文裏也有提到如何用 eclipse 包出一個含有 path 的 jar 檔,簡述如下:
 
    1. 專案上按右鍵跳出選單,選「Export」-->「Export」,會跳出小視窗
    2. 在跳出的小視窗上選「Java」-->「JAR file」,然後按下「Next」鈕,進入包 jar 的視窗。
    3. 在包 jar 的視窗裏勾選完要包入 jar 的檔案與 jar 檔路徑。
    4. 在同一視窗裏,勾選未於下方 Options 項次裏的「Add directory entries」。
    5. 最後按「Finish」鈕完成。
 
在勾選了 Add directory entries 後重包了 jar 檔,再用 ClassLoader 的 getResource() 去載入位於 jar 檔內的 path,果然回傳不再是 null 了。接著趕緊將新包的 jar 檔放入專案內去執行,但結果還是一樣,位於 jar 檔內的 Spring 配置檔仍是無法讀入,於是再去看了一次官方文件,裏面的 4.7.2.3 節中有提到如果要引入的 Spring 配置檔如果是位於 jar 檔之類非當前的目錄下時,最好要給一個根目錄來識別。
 
會這樣主要是因為 Java ClassLoader.getResource() 方法若是給一個空字串,則它會當成要載入的 path 是當前目錄而不是 jar 檔,於是再修改一下 import 的寫法:
    <import resource="classpath:com/e104/paoservice/**/services.xml"/>
 
重新啟動 Tomcat 後,果然位於 jar 檔內的 Spring 配置檔都能正確讀入了!

arrow
arrow
    全站熱搜

    大笨鳥 發表在 痞客邦 留言(0) 人氣()