Maven插件開發遇坑 - 關于ClassLoader和Resources文件

前言

對于 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 包的具體位置。

// 待續

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,837評論 18 139
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,925評論 6 342
  • 所有項目的構建都是有生命周期的,這個生命周期包括:項目清理、初始化、編譯、測試、打包、集成測試、驗證、部署、站點生...
    zlcook閱讀 2,797評論 0 21
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,829評論 25 708
  • 窮人之所以窮是因為缺錢通常人們遇到稀缺的事物,行為會有所改變,這個稀缺的事物,可以是具體的東西,也可以是時間和金錢...
    曉曉you連閱讀 333評論 0 0