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 包的具体位置。

// 待续

    原文作者:hh23485
    原文地址: https://www.jianshu.com/p/abe7d6905451
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞