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源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索