问:老师,同样的代码,为何我将Java工程改造成Maven后,始终无法运行?
实现的功能:加载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();
}
}
此时,程序能够正常运行。
2.现在将Java工程,改造成基于Maven的形式。目录结构如下。
Demo代码如下。
public
Java工程的classpath是src;Maven工程的classpath有一个是resources。我也做了相应修改。但为何,此时用Maven写的同样功能代码,始终报错如下。
FileNotFoundException:
答:
(赶时间的,可以略过分析,直接看本文最后的结论和源码)
“路径问题”首先得思考一个问题:程序中使用的相对路径,是基于最终执行的字节码路径,还是源码的路径?(比如原文件是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
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
运行结果:
D:githubJavaCoresrcJavaBook.
发现 ,程序在执行时当前路径是在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
很“简单”一个问题,是不是还挺绕人的~
- 完 -
推荐阅读
答疑 | 高并发都要学哪些技术?
答疑 | 我是JAVA初级,有必要学架构设计吗?
Java小白到大神的心路历程(Java SE)
答疑 | 面试全对,却没offer?
答疑 | 背下这300字,面试就能加薪!