Java程序使用Maven後沒法運行?

在公衆號回覆課程,免費獲取JAVA全棧課程java


做者 | 顏 羣git

公衆號 | 大數據和人工智能技術github



問:老師,一樣的代碼,爲什麼我將Java工程改形成Maven後,始終沒法運行?
web


實現的功能:加載abc.txt文件,代碼是寫在了Demo類中。面試

開發工具是Idea。
微信


1.如下是普通Java工程的目錄結構。
架構

Demo代碼以下併發

public class Demo {
    public static void main(String[] args)throws Exception{
        InputStream input = new FileInputStream("src/a/abc.txt") ;
        System.out.println();
    }
}


此時,程序可以正常運行。app


2.如今將Java工程,改形成基於Maven的形式。目錄結構以下。
jvm

Demo代碼以下。

public class Demo {
    public static void main(String[] args)throws Exception{
         InputStream input = new FileInputStream("resources/abc.txt") ;
         System.out.println();
    }
}


Java工程的classpath是src;Maven工程的classpath有一個是resources。我也作了相應修改。但爲什麼,此時用Maven寫的一樣功能代碼,始終報錯以下。

FileNotFoundExceptionresources\abc.txt (系統找不到指定的路徑。)


答:

(趕時間的,能夠略過度析,直接看本文最後的結論和源碼)

「路徑問題」首先得思考一個問題:程序中使用的相對路徑,是基於最終執行的字節碼路徑,仍是源碼的路徑?(好比原文件是A.java,編譯後的文件是A.class。那麼A在加載abc.txt時,「相對路徑」是以「A.java」爲參照點,仍是以「A.class」爲參照點?。


上面這個問題,暫時放一放。先直接看一下形成你疑惑的根本緣由:普通的Java工程和Maven等構件工具,對.class文件和靜態資源的打包路徑不一樣。


1.打開普通Java工程中 字節碼目錄,以下。

發現了什麼?在普通Java工程中在編譯及運行階段,並不會處理靜態資源(也就是會忽略abc.txt文件)。所以,要加載abc.txt,就得去它原來的位置,即在src源碼目錄下,如圖所示。


因此,在使用普通Java工程時,就須要在src下面找abc.txt(由於字節碼目錄中的靜態資源,會被忽略)。所以,加載路徑是源碼src中的路徑,而不是字節碼classes中的路徑,以下。

new FileInputStream("src/a/abc.txt"


2.但Maven工程對靜態資源的處理方式則不一樣。

咱們知道,Maven會將字節碼和靜態資源 都打包在 target下,如圖所示。

也就是說,maven會將Demo.class和abc.txt一同打包在 字節碼(target/classes)目錄下。但要注意:maven默認在讀取路徑時, 是基於字節碼classes目錄,而不是源碼src目錄,這與普通Java工程徹底相反。【由於maven的一個原則:就是想讓 最終的執行程序,與源碼相互隔離,互不干擾】。因此,若是使用了maven,靜態資源的相對路徑獲取方式,就和普通Java工程不同了(不能再從src中讀取靜態資源,而要從classes中讀取)。


講到這裏,有同窗可能會問「看上圖,可知abc.txt就在Demo.class的上一級。所以在Demo.class中使用../abc.txt不就好了?」。看起來好像能夠,但實際也不行。


使用../abc.txt的意思是,從當前路徑開始,尋找上一級目錄。這裏說的當前路徑好像就是字節碼路徑中的Demo.class文件自己。但實際狀況真的是嗎?使用如下代碼,查看一下當前路徑究竟是什麼。

public class Demo {
    public static void main(String[] args)throws Exception{//查看「當前路徑       String path =   new File(".").getAbsolutePath() ;
        System.out.println(path);
    }
}

運行結果:

D:\github\JavaCore\src\JavaBook\.


發現 ,程序在執行時當前路徑是在src下,根本不是classes字節碼。這又與Maven的原則相違背(Maven默認讀取的路徑是字節碼classes目錄,而不是源碼src目錄)。【這種特性是jvm底層決定的,咱們沒法改變】。


以上,有些繞,總結就是:

java程序在使用相對路徑,加載靜態資源時:

1.普通Java工程加載的是源文件src目錄中的靜態資源;

2.Maven工程加載的是字節碼目錄target/classes中的靜態資源;

3.在編寫源碼時,程序中相對路徑基於的「當前路徑是在源文件src目錄下 ,不是在classes目錄下。(也就是當前路徑是基於A.java,而不是基於A.class)。


以上三條中,「1」和「3」是一致的,因此普通Java工程方式加載靜態資源,沒有什麼,直接寫相對路徑就行;但「2」和「3」在讀取路徑時是矛盾的,所以Maven工程在加載靜態資源時,就不能使用相對路徑,而須要使用絕對路徑。


但還要注意,絕對路徑要以動態的方式獲取,防止不一樣環境之間的差別。


最後,給出Maven方式,獲取靜態資源的代碼。


public class Demo {
    public static void main(String[] args)throws Exception{//動態方式,獲取abc.txt的絕對路徑
         String path = Demo.class.getClassLoader().getResource("abc.txt").getPath();
         InputStream input = new FileInputStream(path) ;
         System.out.println(path);
    }
}


很「簡單」一個問題,是否是還挺繞人的~


- 完 -

推薦閱讀

答疑 | 高併發都要學哪些技術?

答疑 | 我是JAVA初級,有必要學架構設計嗎?

Java小白到大神的心路歷程(Java SE)

答疑 | 面試全對,卻沒offer?

答疑 | 背下這300字,面試就能加薪!


掃描上方二維碼回覆 課程
便可得到JAVA全棧教程合集 
30+課程掌握 95% 的開發技能

 以爲有用,請點在看  ↓ 

本文分享自微信公衆號 - 大數據和人工智能技術(Big_Data-AI)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索