前言
對于 Java 開發人員來說,寫一個配置文件是非常常見的,比如日志,又比如早期的 Spring,以及讓人又愛又恨的 mybatis 和 hibernate 到現在也沒有擺脫各種配置文件。
至少在某種層面上來說,讀一個配置文件、寫一個配置文件,是最基礎不過、最必須掌握的事情了。
所以很多的時候,我們簡單的寫下:
Properties properties = new Properties();
properties.load(new FileInputStream("config.properties"));
然后,我們就開始了讀取數據。
當然有些人可能小心一些,畢竟是從 classpath 讀資源文件,所以他們喜歡用 ClassLoader
來讀取,例如:
File configFile = this.getClassLoader().getResources("config.properties"));
Properties properties = new Properties();
properties.load(configFile);
習以為常之后,我根本沒有意識到這有什么問題。
問題出現
這兩天問題出現了,我們計劃在寫一個 Maven 插件,對于一個插件來說,一個配置文件也是少不了的,至少你需要配置一下我在哪個項目里、做什么事情、怎么做。
所以,我們寫了一個配置文件,用來連接數據庫,就像你們經常做的那樣:
db.username = xxx
db.password = xxx
db.driver = com.mysql.jdbc.Driver
db.url = xxx
然后保存成 database.properties
存放在 resources
的根目錄下,這是一個 maven 的項目,maven 已經幫我們設置了 classPath,并讓 resources
文件夾成為了 resources root
類型的 path。
然后我開始了讀取,在maven插件的項目里,所有的程序入口,都在一個 execute
的方法實現里。
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
Props props = new Props("database.properties");
getLog().info("get configuration of ")
try {
properties.load(new FileInputStream("database.properties"));
for(Object p : properties.keySet()){
getLog().info(props.getStr(p.toString()));
}
} catch (IOException e) {
getLog().error("error ", e);
}
}
ok,一切正常,我開始了測試,就像所有 maven 的項目一樣:
// 現在顯然還不需要測試
mvn clean package install -DsktipTest
然后在另外一個項目的pom文件里引用在 <build>
<plugins>
<plugin>
標簽下。
然后。。。
[圖片上傳失敗...(image-fcc351-1516635482197)]
WTF???
No such file or directory...
Ok,下面來檢查一下。。。
檢查
檢查首先需要看看文件是不是存在。
嗯,存在,沒毛病。
[圖片上傳失敗...(image-d9347e-1516635482197)]
那么接下來的問題就是,為什么沒有找到。
看看剛才輸出的路徑:
// reverse-maven-plugin是工程的名字 v1.0是版本
file:/Users/HMH/.m2/repository/cn/hhchat/reverse-maven-plugin/v1.0/reverse-maven-plugin-v1.0.jar!/database.properties
毫無疑問,這是一個帶了 file:
前綴的路徑,那么應該是一個 URI,然后,指向的是一個名稱為 reverse-maven-plugin-v1.0.jar
的jar包中的 database.properties
。
這大概就是問題了,當我將程序作為一個 maven
插件引用的時候,運行時應該是一個 Jar
包,所以 ClassLoader 沒有辦法直接定位到 database.properties
的位置。
解決方案
原來從 resources
文件夾里讀取文件的需求,變成了從 jar
包的目錄下讀取文件。那么 maven
會把 resources
里的文件放在 jar
包的什么位置呢?
[圖片上傳失敗...(image-19cedb-1516635482197)]
嗯,原來是在 Jar
包的根目錄了,所以,現在需要看看如何從Jar包中讀取文件了。
讀取Jar中的文件
方法1 getResourceAsStream()
這里仍然是兩種辦法,第一種辦法,你可以使用Stream來讀取,這個變動非常小,如下所示即可:
Properties properties = new Properties();
properties.load(LoadProjectJar.class.getResourceAsStream("/database.properties"));
[圖片上傳失敗...(image-aedb1e-1516635482197)]
這說明對于 Jar 包運行狀態下的resources文件,通過 getResourceAsStream()
的方式是可以獲取的文件數據的。
方法2 JarFile
使用 JarFile 來連接 jar 包中的內容是另外一種辦法,可以從 jar 包中讀取到文件和數據。對于 Maven 來說,這也是一種好辦法,因為你可以從 Maven 運行時通過 getClassLoader()
來獲取 jar 包的具體位置。
// 待續