一、問題引入
最近使用如下方式載入配置檔案時總是傳回
null
:
Thread.currentThread().getContextClassLoader().getResource("config.properties")
配置檔案說明:檔案放置在與
config.properties
目錄同級的
src
目錄中。
config
二、問題分析
檢視API文檔發現關于類ClassLoader方法
getResource
的傳回值有如下描述:
讀取資源的 URL 對象;如果找不到該資源,或者調用者沒有足夠的權限擷取該資源,則傳回 null。
由文檔API可知,傳回null有兩種原因引起:
- 找不到該資源;
- 對該資源沒有擷取權限。
這裡顯然可以排除第2中原因,那麼明明config/config.properties檔案存在,為什麼會找不到呢?
原因和Java Resource資源載入路徑有關。
預設情況下,Java在載入資源時,隻會在工程的
classpath
下尋找。
這裡需要說明的是對classpath的認識不要局限在隻是在這裡尋找二進制class檔案、jar包,Java還會在這裡尋找文本檔案(例如配置檔案),圖像,聲音資源等。
為了一探究竟,我們列印出classpath,可以通過如下兩種方式:
- 擷取屬性
:java.class.path
System.getProperty("java.class.path")
- 利用如下代碼段:
ClassLoader classLoader = ClassLoader.getSystemClassLoader(); //Get the URLs URL[] paths = ((URLClassLoader)sysClassLoader).getURLs(); for(int i=; i< paths.length; i++) { System.out.println(paths[i].getFile()); }
以上兩種方式,得到的
classpath
結果相同:
/Users/zq/Documents/workspace/yourProjectName/bin/
/Users/zq/Documents/workspace/yourProjectName/lib/ant.jar
/Users/zq/Documents/workspace/yourProjectName/lib/commons-logging-.jar
/Users/zq/Documents/workspace/yourProjectName/lib/log4j-.jar
/Users/zq/Documents/workspace/yourProjectName/lib/mysql-connector-java--bin.jar
/Users/zq/Documents/workspace/yourProjectName/lib/httpclient-.jar
/Users/zq/Documents/workspace/yourProjectName/lib/httpcore-.jar
/Users/zq/Documents/workspace/yourProjectName/lib/commons-codec-.jar
/Users/zq/Documents/workspace/yourProjectName/lib/commons-lang-.jar
/Users/zq/Documents/workspace/yourProjectName/lib/mail-.jar
/Users/zq/Documents/workspace/yourProjectName/lib/trove-a6.jar
其中可以看出
classpath
中并沒有包含
config/config.properties
。
三、問題解決
到目前為止,問題的原因已經搞清楚了,那麼問題的解決也就迎刃而解了:
隻要把
config/config.properties
添加到工程的
build path
中即可。
再次列印出
classpath
,可以看到最後一行已經包含了
config
目錄:
······
/Users/zq/Documents/workspace/yourProjectName/lib/commons-lang-.jar
/Users/zq/Documents/workspace/yourProjectName/lib/mail-.jar
/Users/zq/Documents/workspace/yourProjectName/lib/trove-a6.jar
/Users/zq/work_xxx/yourProjectName/config/
四、深入探究
在Java工程中,擷取資源一般通過如下兩種方式(相應的getResourceAsStream方法傳回的是同一資源的流形式inputstream):
- Class.getResource()
- ClassLoader.getResource()
ClassLoader的擷取: 1. Thread.currentThread().getContextClassLoader() 2. clazz.getClassLoader() 3. ClassLoader. getSystemClassLoader()
兩者的差別為:第一種方式在相對clazz的路徑中尋找資源;第二種方式是在整個classpath中尋找資源。
兩者的共同點為:都在
classpath
中尋找資源。
最後需要說明的是:
Java中不存在标準的相對路徑,各種相對路徑取資源的方式都是基于某種規則轉化為絕對路勁,但是在程式設計過程中,絕對不要直接使用絕對路徑。
是以,我們在使用Java載入Resource資源時,隻要尋找到合适的參考基點,就能很輕松得定位你要找的resource資源,一般情況下參考基點有如下幾種:
-
classpath:
本博文已經詳細的做了介紹,這裡不再做贅述。
- 目前工程目錄(強烈不推薦使用,會帶來移植問題)
System.getProperty("user.dir")
-
Web應用程式的根目錄
在Web應用程式中,一般通過
方法得到Web應用程式的根目錄的絕對路徑。ServletContext.getRealPath("/" )
五、參考連結:
http://blog.csdn.net/cutesource/article/details/6141768
http://blog.csdn.net/ak913/article/details/7399056