美文网首页
Maven插件开发遇坑 - 关于ClassLoader和Reso

Maven插件开发遇坑 - 关于ClassLoader和Reso

作者: hh23485 | 来源:发表于2018-01-22 23:38 被阅读240次

    前言

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

    // 待续

    相关文章

      网友评论

          本文标题:Maven插件开发遇坑 - 关于ClassLoader和Reso

          本文链接:https://www.haomeiwen.com/subject/vlekoxtx.html