springboot开发笔记-(8)-配置文件的加载顺序

  1. 8.1 配置文件的优先级
  2. 8.2 配置文件的优先级-代码证明
    1. 8.2.1 代码核心文件
    2. 8.2.2 执行流程
  3. 8.3 官网说明
  4. 8.4 加载优先级总结(按高到底:)

8.1 配置文件的优先级

server.servlet.context-path=/app
server.port=8888
spring.config.location=xxx/xxx/application.properties

下面本文中说到"级别高"意思就是会替换其他的, 以它为首选, 它最终会起作用, 其他的会被覆盖;

本节要回答的问题:springboot应用部署后, 配置文件以哪个为准? 假如应用打包成可执行app.jar后有以下这几个配置文件:

  1. jar同目录的 application.properties; ->官网称此为: file:./config/
  2. jar同目录的 config/application.properties; ->官网称此为: file:./config/
  3. jar内部jar包中的 classes/application.properties; ->官网称此为: classpath:/
  4. jar内部jar包中的 classes/config/application.properties; ->官网称此为: classpath:/config/
  5. 启动参数时直接覆盖某个单项配置, 比如改端口号: java -jar app.jar --server.port=9999来指定;
  6. 随便指定一个地址放置 application.properties , 使用 启动参数spring.config.location=xxx来指定; (注意: 这个配置实测会互补失效–即: 只有它自己起作用)

–let’s guess:

我们先来做一个猜测, 如果是让我们自己设计, 想象实际上线的场景, 我们会期望哪个优先级最高(最终会覆盖其他配置的)?

如果我在线上部署了一个app.jar文件, 执行java -jar app.jar 启动应用; 启动之后线上如果有问题了, 比如端口被占用, 比如数据库配置修改, 我需要马上调整一个参数, 最快的方式是什么?

  1. 首先: 直接重启, java -jar app.jar --some.prop=new_value 肯定是这个最快, 或者干脆自己指定一个配置文件的地址, –参数加命令行后面; (上面5/6)

  2. 除了执行带参数, 方便修改的肯定是 jar平级目录下了, 那么, 应该轮到 app.jar平级目录下的配置了:

    是设置哪个级别高呢? 直接读取application.properties? 还是 config/application.properties?

    有的人认为 config很直观, 就把它下面的设为高级别—没错—springboot的设计者就是这类的(上面2);

  3. 当然 紧接着就是平级的了(上面1)

  4. 所以jar包里面的两处, 应该是低级别的了, 按照第2点的逻辑, 应该是 classpath:/config/application.properties 级别高于 classpath:application.properties;

所以我们就大概出来一个思路, 配置起作用优先级别依次是:

  1. 启动时指定某些参数

    java -jar app.jar --server.port=9999

  2. 启动时指定配置文件(有坑~)

    java -jar app.jar -spring.config.location=/mydir/application.properties

  3. jar同目录的config/application.properties

    app.jar 同级别目录下的 ./config/application.properties

  4. jar同目录的application.properties

    app.jar同级别目录下的 application.properties

  5. jar内部 classpath目录下的 ./config/application.properties

    app.jar/BOOT-INF/classes/config/application.properties

  6. jar内部classpath目录下的 application.properties

    app.jar/BOOT-INF/classes/application.properties

注意: 2处之所以说有坑是因为:

  1. 其他的配置文件只是优先级不同, 所有的配置文件还都是可以加载互补的, 只是优先级更高的会覆盖优先级低的
  2. 但是2处这个怂配置则不然: 假如你指定了 -spring.config.location=xxx , 你要小心了, 这相当于是个渣男: 他只顾自己, 不和其他的互补, 别的都被忽略了!!!

8.2 配置文件的优先级-代码证明

8.2.1 代码核心文件

  1. idea里新建一个springboot的module: springboot-02-config, 创建了4个配置文件, 配置对应关系如图:

image.png

  1. pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.2.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.niewj</groupId>
        <artifactId>springboot-02-config</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>springboot-02-config</name>
        <description>springboot-2-config</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>com.google.code.gson</groupId>
                <artifactId>gson</artifactId>
                <version>2.8.6</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.10</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    
        <build>
            <finalName>app</finalName>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
  2. person.java

    package com.niewj.springboot.model;
    
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * Created by niewj on 2020/8/5 23:20
     */
    @Data
    @Component
    @ConfigurationProperties(prefix = "person")
    public class Person {
    
        private Integer age;
        private String lastName;
        private boolean student;
        private String location;
    
        private List<String> hobbies;
    }
  3. controller:

    package com.niewj.springboot.controller;
    
    import com.niewj.springboot.model.Person;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * Created by niewj on 2020/8/5 23:17
     */
    @RestController
    public class HelloController {
    
        @Autowired
        private Person person;
    
        @RequestMapping("/hello")
        public Object hello(){
            return person;
        }
    }

8.2.2 执行流程

  1. 编译打包

    mvn clean install -Dmaven.test.skip=true

  2. 打包后生成一个 app.jar可执行文件

  3. show in explore 进入 app.jar所在目录, 我们选择把jar包复制到其他目录, 比如: E:/deploy/app.jar

  4. 目录下shift+右键->在此处打开命令行窗口

    config(目录下有application.properties)
    app.jar
    application.properties

  5. 在命令行java -jar app.jar

    PS E:\deploy> java -jar .\app.jar
    
      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::        (v2.2.2.RELEASE)
    
    2020-08-06 13:23:53.011  INFO 20304 --- [           main] com.niewj.springboot.ConfigApplication   : Starting ConfigApplication v0.0.1-SNAPSHOT on LAPTOP-7EINAF4M with PID 20304 (E:\deploy\app.jar started by niewj in E:\deploy)
    2020-08-06 13:23:53.015  INFO 20304 --- [           main] com.niewj.springboot.ConfigApplication   : No active profile set, falling back to default profiles: default
    2020-08-06 13:23:56.206  INFO 20304 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8004 (http)
    2020-08-06 13:23:56.225  INFO 20304 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
    2020-08-06 13:23:56.226  INFO 20304 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.29]
    2020-08-06 13:23:56.343  INFO 20304 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
    2020-08-06 13:23:56.343  INFO 20304 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3275 ms
    2020-08-06 13:23:56.512  INFO 20304 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
    2020-08-06 13:23:56.721  INFO 20304 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8004 (http) with context path ''
    2020-08-06 13:23:56.724  INFO 20304 --- [           main] com.niewj.springboot.ConfigApplication   : Started ConfigApplication in 4.112 seconds (JVM running for 4.652)

    可以看到, 使用的是端口: 8004 , 再通过 http://localhost:8004/hello 访问, 显示:

    {"age":30,"lastName":"wj","student":false,"location":"file/config/application.properties","hobbies":["8004","running","coding","cooking"]}

    –> 可见起作用的是: app.jar同目录下的 config/application.properties

  6. 我们删掉这个目录再试一次:

    PS E:\deploy> java -jar .\app.jar
    
      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::        (v2.2.2.RELEASE)
    
    2020-08-06 13:27:45.312  INFO 7716 --- [           main] com.niewj.springboot.ConfigApplication   : Starting ConfigApplication v0.0.1-SNAPSHOT on LAPTOP-7EINAF4M with PID 7716 (E:\deploy\app.jar started by niewj in E:\deploy)
    2020-08-06 13:27:45.315  INFO 7716 --- [           main] com.niewj.springboot.ConfigApplication   : No active profile set, falling back to default profiles: default
    2020-08-06 13:27:48.470  INFO 7716 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8003 (http)
    2020-08-06 13:27:48.482  INFO 7716 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
    2020-08-06 13:27:48.483  INFO 7716 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.29]
    2020-08-06 13:27:48.591  INFO 7716 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
    2020-08-06 13:27:48.592  INFO 7716 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3227 ms
    2020-08-06 13:27:48.754  INFO 7716 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
    2020-08-06 13:27:48.954  INFO 7716 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8003 (http) with context path ''
    2020-08-06 13:27:48.957  INFO 7716 --- [           main] com.niewj.springboot.ConfigApplication   : Started ConfigApplication in 4.081 seconds (JVM running for 4.606)

    可以看到, 使用的是端口: 8003, 再通过 http://localhost:8003/hello 访问, 显示:

    {"age":30,"lastName":"wj","student":false,"location":"file/application.properties","hobbies":["8003","running","coding","cooking"]}

    –> 可见起作用的是: app.jar同目录下的 ./application.properties

    1. 删掉./application.properties再试:
    PS E:\deploy> java -jar .\app.jar
    
      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::        (v2.2.2.RELEASE)
    
    2020-08-06 13:31:42.852  INFO 3700 --- [           main] com.niewj.springboot.ConfigApplication   : Starting ConfigApplication v0.0.1-SNAPSHOT on LAPTOP-7EINAF4M with PID 3700 (E:\deploy\app.jar started by niewj in E:\deploy)
    2020-08-06 13:31:42.855  INFO 3700 --- [           main] com.niewj.springboot.ConfigApplication   : No active profile set, falling back to default profiles: default
    2020-08-06 13:31:46.018  INFO 3700 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8002 (http)
    2020-08-06 13:31:46.032  INFO 3700 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
    2020-08-06 13:31:46.033  INFO 3700 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.29]
    2020-08-06 13:31:46.144  INFO 3700 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
    2020-08-06 13:31:46.145  INFO 3700 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3239 ms
    2020-08-06 13:31:46.306  INFO 3700 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
    2020-08-06 13:31:46.509  INFO 3700 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8002 (http) with context path ''
    2020-08-06 13:31:46.514  INFO 3700 --- [           main] com.niewj.springboot.ConfigApplication   : Started ConfigApplication in 4.051 seconds (JVM running for 4.579)

    可以看到, 使用的是端口: 8002, 再通过 http://localhost:8002/hello 访问, 显示:

    {"age":30,"lastName":"wj","student":false,"location":"resource/config/application.properties","hobbies":["8002","running","coding","cooking"]}

    –> 可见起作用的是: app.jar包内的classpath目录下的: classpath:config/application.properties

    1. 到此就不用再试了, 如果没有config目录, 肯定读取的是classpath: application.properties了, 这个我们平时用的就是它;

    正好证实了上面的结论.

    1. 我们再试试 spring.config.location命令行指定配置文件的执行方式: 在桌面上放了一个 application.properties, 内容如下:

      server.port=8333
      
      person.hobbies=8333,running,coding,cooking
      person.location=spring.config.location/application.properties
      
    2. java -jar app.jar --spring.config.location=C:\Users\weiju\Desktop\application.properties

      PS E:\deploy> java -jar app.jar --spring.config.location=C:\Users\weiju\Desktop\application.properties
      
        .   ____          _            __ _ _
       /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
      ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
       \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
        '  |____| .__|_| |_|_| |_\__, | / / / /
       =========|_|==============|___/=/_/_/_/
       :: Spring Boot ::        (v2.2.2.RELEASE)
      
      2020-08-06 13:39:40.251  INFO 20548 --- [           main] com.niewj.springboot.ConfigApplication   : Starting ConfigApplication v0.0.1-SNAPSHOT on LAPTOP-7EINAF4M with PID 20548 (E:\deploy\app.jar started by niewj in E:\deploy)
      2020-08-06 13:39:40.254  INFO 20548 --- [           main] com.niewj.springboot.ConfigApplication   : No active profile set, falling back to default profiles: default
      2020-08-06 13:39:43.357  INFO 20548 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8333 (http)
      2020-08-06 13:39:43.368  INFO 20548 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
      2020-08-06 13:39:43.368  INFO 20548 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.29]
      2020-08-06 13:39:43.452  INFO 20548 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
      2020-08-06 13:39:43.453  INFO 20548 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3142 ms
      2020-08-06 13:39:43.615  INFO 20548 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
      2020-08-06 13:39:43.805  INFO 20548 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8333 (http) with context path ''
      2020-08-06 13:39:43.809  INFO 20548 --- [           main] com.niewj.springboot.ConfigApplication   : Started ConfigApplication in 3.997 seconds (JVM running for 4.531)

      可以看到, 使用的是端口: 8333, 再通过 http://localhost:8333/hello 访问, 显示:

      {"age":null,"lastName":null,"student":false,"location":"spring.config.location/application.properties","hobbies":["8333","running","coding","cooking"]}

      –> 同样: 证明了渣男属性 spring.config.location : 只顾自己, 别人都抛弃了, 没有了互补功能;

    需要注意的几点:

    1. 我们可以看到他们之间除了优先级, 其他的是都加载的, 是互补的关系(命令行带参spring.config.properties除外)
    2. 上面的测试, 除了删除之外, 改名也生效, 名字不是 application.properties/application.yml都不会认的;
    3. 我们没有试命令行指定某个参数, 比如 java -jar app.jar --server.port=8080 这个; 它是第一优先级!

8.3 官网说明

4.2.3. Application Property Files


SpringApplication loads properties from application.properties files in the following locations and adds them to the Spring Environment:

  1. A /config subdirectory of the current directory
  2. The current directory
  3. A classpath /config package
  4. The classpath root

The list is ordered by precedence (properties defined in locations higher in the list override those defined in lower locations).

……

Config locations are searched in reverse order. By default, the configured locations are classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/. The resulting search order is the following:

  1. file:./config/
  2. file:./config/*/
  3. file:./
  4. classpath:/config/
  5. classpath:/

8.4 加载优先级总结(按高到底:)

优先级高的会覆盖低的, 也可以理解他们的加载时机是顺序相反的!

  1. 启动时指定某些参数 > java -jar app.jar --server.port=9999

  2. 启动时指定配置文件(有坑:互补失效!)

java -jar app.jar -spring.config.location=/mydir/application.properties

  1. jar同目录的config/application.properties

app.jar 同级别目录下的 ./config/application.properties

  1. jar同目录的application.properties

app.jar同级别目录下的 application.properties

  1. jar内部 classpath目录下的 ./config/application.properties

app.jar/BOOT-INF/classes/config/application.properties

  1. jar内部classpath目录下的 application.properties

    app.jar/BOOT-INF/classes/application.properties


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 hi@niewj.com

×

喜欢就点赞,疼爱就打赏