• 拒绝FileNotFoundException!总结了这几个读取jar包外配置文件的知识点


    前言

    相信很多人遇到过这个问题:本地运行的好好的程序,怎么部署到线上就报找不到配置呢?

    初识getResource
    案例一
      FieldMapConfig.class.getResource("p1.properties").getPath();
    	```
    	
    	- 这段代码在本地运行没有任何问题,一放到线上就报空指针。
    
    
    ###### 案例二
    
    ![file](https://graph.baidu.com/resource/22243f231967f8c552ea801577605576.png)
    
    - 读取配置,报错FileNotFoundException。
    - 乍一看,两段代码好像没有什么区别,但是细心的你,应该发现:
    

    App.class.getClassLoader().getResource("p1.properties").getPath();
    FieldMapConfig.class.getResource("p1.properties")

    - 一个使用当前class的api,一个使用的当前class的classLoader的api来获取的,这有什么区别呢?请听我细细分说。
    
    ##### Class和ClassLoader
    
    - 秉着探索的态度,我写了一个例子,请看:
    
    

    public static void main( String[] args ) {

        if (args.length != 1) {
            System.out.println("usage: java -jar com.hyq.simple-1.0.jar args");
            return;
        }
    
        System.out.println("App.class.getResource(args[0]):");
        System.out.println(App.class.getResource(args[0]));
        System.out.println();
    
        System.out.println("App.class.getClassLoader().getResource(args[0]):");
        System.out.println(App.class.getClassLoader().getResource(args[0]));
        System.out.println();
    
        System.out.println("App.class.getResourceAsStream(args[0]):");
        System.out.println(App.class.getResourceAsStream(args[0]));
        System.out.println();
    
        System.out.println("App.class.getClassLoader().getResourceAsStream(args[0]):");
        System.out.println(App.class.getClassLoader().getResourceAsStream(args[0]));
        System.out.println();
    
    }
    
    
    - 验证如下:
    
    ![file](https://img2018.cnblogs.com/blog/894494/201912/894494-20191229171443615-244970716.jpg)
    
    - 从上图可以看出,使用当前类的GetResource和当前类的classloader的getResource,
    获取到的配置有区别。怎么解释呢?
    
    前者是读取的当前类的包目录下的配置文件
    
    后者读取的是,jar包内部,根目录的配置文件。
    
    总结:当读取配置的路径不是以/开头时,会按相对路径读取,相对的是当前类的class 这个文件,而采用class的classLoader则是相对于根路径(也就是我们说的classpath)。
    
    
    ##### 各种路径试验
    
    - 如果你还在为相对路径,配置文件前面带不带/,等一系列问题折腾,那不如动手做做试验看看,代码还是上面那段代码,通过动态传入配置文件的路径来读取,试验结果如下:
    
    ![file](https://img2018.cnblogs.com/blog/894494/201912/894494-20191229171443871-77831805.jpg)
    
    ##### 为什么推荐使用getResourceAsStream?
    
    - 形如:"jar:file:/data/simpleJava/com.hyq.simple-1.0.jar
    !/p1.properties" 这样的路径,getResource是无法读取的,因为他不是一个文件路径。
    而getResourceAsStream会以流的方式,打开文件来读取数据,上图的文件树,就是我用unzip命令解压jar包后显示出来的。
    
    ##### springboot加载配置
    默认情况下,springboot会加载名为application的properties或者yml文件。
    其中查找的顺序为:
    - 1、当前jar包所在目录的config目录下。
    - 2、当前目录。
    - 3、jar包内classpath的config目录。
    - 4、jar包内classpath目录。
    
    注意:重复定义的配置,会被后者覆盖。
    
    ###### 通过名字动态加载配置?
    
    ###### 知识点一
    - boot配置的语法是,凡是以--开头(两个横线)的配置,会被解析。
    相信大家可能遇到过这样一个场景,同一个jar包要启动多次,每个进程的配置不一样,端口不同。
    
    ![file](https://img2018.cnblogs.com/blog/894494/201912/894494-20191229171444257-525834636.jpg)
    
    ###### 知识点二
    通过--spring.config.name 指定配置文件名即可。
    还有一种新奇的方式,直接通过spring.application.json传递json,案例如下:
    

    java -Dspring.application.json='{"name":"test"}' -jar myapp.jar

    
    ###### 知识点三
    当然,你也可以指定多个配置文件,方式如下:
    

    java -jar myproject.jar
    --spring.config.location=classpath:/p1.properties,classpath:/p2.properties

    值得注意的是,config配置文件搜索的顺序和指定的顺序是刚好相反的。
    
    ###### 知识点四
    通过spring.profiles.active属性可以指定那个环境下的配置。
    
    ![file](https://img2018.cnblogs.com/blog/894494/201912/894494-20191229171444449-2036003783.jpg)
    这里我比较喜欢定义两个yml,然后在application.yml中指定对应环境的配置。
    

    spring:
    profiles:
    active: prod
    ```

    知识点五

    可以通过@value注解来获取变量值

    @Value("${app.init.welcome-msg:侠梦的开发笔记}")
    private String msg;
    

    也可以通过@ConfigurationProperties("app.init")注解,放在类来获取整个配置。

    总结
    • 本章节我们做了实验,了解了getResource和getResourceAsStream的区别。
    • 学习了springboot通过动态指定配置名,读取配置。
    • 指定读取多个配置文件。
    • 不同运行环境获取不同配置的方式。

    欢迎来公众号【侠梦的开发笔记】 一起交流进步

  • 相关阅读:
    HttpRunner3.X
    基于C++的ByteBuf封装
    关于matlab的配色
    关于样本方差的无偏估计
    使用Python求解Nonogram
    菜鸡的一些力扣记录
    LeetCode链表练习
    C语言中的链表
    Python中的链表简介
    Nebula Graph 源码解读系列 | Vol.03 Planner 的实现
  • 原文地址:https://www.cnblogs.com/hyq0823/p/12115553.html
Copyright © 2020-2023  润新知