2007/7/6

Spring提供的資源搜尋器 PathMatchingResourcePatternResolver

過去在尋找設定檔的時候,總是得先用context.getRealPath("/")找到webapp實體的硬碟位置後,才能逐步以File的方式,尋找每一個設定檔,但是這種方法,在weblogic裡面卻行不通了,因為weblogic以context.getRealPath("/")回傳的結果跟tomcat不同。

這個時候突然想到先前在weblogic上設定spring-hibernate的方法(ex: classpath*:/**/mappings/mysql/**/*.hbm.xml),於是就先去把spring source code抓回來,然後trace這個部份是怎麼寫的。很幸運的是,這一切都是靠一個類別org.springframework.core.io.support.PathMatchingResourcePatternResolver就做完了,因此我就有了一個能在webapp上尋找設定檔的方式,連同在stand-alone的junit test也能運作。

至於這個PathMatchingResourcePatternResolver到底是怎麼做的,把spring framework log4j的 log level設定為info(log4j.logger.org.springframework=info),就能發現PathMatchingResourcePatternResolver把整個classpath裡所有的資源包含jar檔都能掃描一次,如果設定的參數為硬碟路徑(mappingDirectoryLocations),spring就能把該路徑下所有的子目錄都查過一次。至於classpath,包含jar檔的部分,spring則是以class loader提供的getXXXResource methods做出來的,詳細的實作方式我也不清楚,反正直接把PathMatchingResourcePatternResolver拿來就很好用了。

但因為class loader本身的限制,先前這種pattern的寫法**/config/**/mappings/mysql/**/*.hbm.xml,得把一開始的prefix路徑寫上去,改成classpath*:config/**/mappings/mysql/**/*.hbm.xml。

最後,先把大多數可能的package prefix都列出來
String[] prefix={"config", "tw", "com" ... };
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
for (int i = 0; i < prefix.length; i++) {
if (prefix[i] != null & !prefix[i].equals("")) {
Resource[] resources = resolver.getResources("classpath*:" + prefix[i] + "/**/configsomething/config-*.xml");
}
}

這樣就能找到在classpath裡面包含jar檔裡面,所有符合/**/configsomething/config-*.xml這個pattern的資源,回傳的資源類別為org.springframework.core.io.Resource,只要用getInputStream()這個method就能取得該資源檔案的InputStream。

ps. 這種方式只適合在app server打開時,init webapp時使用,換句話說,Spring的ApplicationContext在一個webapp裡面只需要建立一次,大家共用就可以了。