8.1 配置文件的优先级
server.servlet.context-path=/app server.port=8888 spring.config.location=xxx/xxx/application.properties
下面本文中说到
"级别高"
意思就是会替换其他的, 以它为首选, 它最终会起作用, 其他的会被覆盖;
本节要回答的问题:springboot应用部署后, 配置文件以哪个为准? 假如应用打包成可执行app.jar后有以下这几个配置文件:
- jar同目录的 application.properties;
->官网称此为: file:./config/
- jar同目录的 config/application.properties;
->官网称此为: file:./config/
- jar内部jar包中的 classes/application.properties;
->官网称此为: classpath:/
- jar内部jar包中的 classes/config/application.properties;
->官网称此为: classpath:/config/
- 启动参数时直接覆盖某个单项配置, 比如改端口号:
java -jar app.jar --server.port=9999
来指定; - 随便指定一个地址放置 application.properties , 使用 启动参数
spring.config.location=xxx
来指定; (注意: 这个配置实测会互补
失效–即: 只有它自己起作用)
–let’s guess:
我们先来做一个猜测, 如果是让我们自己设计, 想象实际上线的场景, 我们会期望哪个优先级最高(最终会覆盖其他配置的)?
如果我在线上部署了一个app.jar文件, 执行
java -jar app.jar
启动应用; 启动之后线上如果有问题了, 比如端口被占用, 比如数据库配置修改, 我需要马上调整一个参数, 最快的方式是什么?
首先: 直接重启,
java -jar app.jar --some.prop=new_value
肯定是这个最快, 或者干脆自己指定一个配置文件的地址, –参数加命令行后面; (上面5/6)除了执行带参数, 方便修改的肯定是 jar平级目录下了, 那么, 应该轮到 app.jar平级目录下的配置了:
是设置哪个级别高呢? 直接读取application.properties? 还是 config/application.properties?
有的人认为 config很直观, 就把它下面的设为高级别—没错—springboot的设计者就是这类的(上面2);
当然 紧接着就是平级的了(上面1)
所以jar包里面的两处, 应该是低级别的了, 按照第2点的逻辑, 应该是 classpath:/config/application.properties 级别高于 classpath:application.properties;
所以我们就大概出来一个思路, 配置起作用优先级别依次是:
启动时指定某些参数
java -jar app.jar --server.port=9999
启动时指定配置文件(有坑~)
java -jar app.jar -spring.config.location=/mydir/application.properties
jar同目录的config/application.properties
app.jar 同级别目录下的 ./config/application.properties
jar同目录的application.properties
app.jar同级别目录下的 application.properties
jar内部 classpath目录下的 ./config/application.properties
app.jar/BOOT-INF/classes/config/application.properties
jar内部classpath目录下的 application.properties
app.jar/BOOT-INF/classes/application.properties
注意: 2处之所以说有坑是因为:
- 其他的配置文件只是优先级不同, 所有的配置文件还都是可以加载互补的, 只是优先级更高的会覆盖优先级低的
- 但是2处这个怂配置则不然: 假如你指定了 -spring.config.location=xxx , 你要小心了, 这相当于是个渣男: 他只顾自己, 不和其他的互补, 别的都被忽略了!!!
8.2 配置文件的优先级-代码证明
8.2.1 代码核心文件
- idea里新建一个springboot的module:
springboot-02-config
, 创建了4个配置文件, 配置对应关系如图:
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>
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; }
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 执行流程
编译打包
mvn clean install -Dmaven.test.skip=true
打包后生成一个
app.jar
可执行文件show in explore
进入 app.jar所在目录, 我们选择把jar包复制到其他目录, 比如: E:/deploy/app.jar目录下
shift+右键->在此处打开命令行窗口
config(目录下有application.properties)
app.jar
application.properties在命令行
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
我们删掉这个目录再试一次:
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
- 删掉./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
- 到此就不用再试了, 如果没有config目录, 肯定读取的是classpath: application.properties了, 这个我们平时用的就是它;
正好证实了上面的结论.
我们再试试
spring.config.location
命令行指定配置文件的执行方式: 在桌面上放了一个 application.properties, 内容如下:server.port=8333 person.hobbies=8333,running,coding,cooking person.location=spring.config.location/application.properties
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
: 只顾自己, 别人都抛弃了, 没有了互补
功能;
需要注意的几点:
- 我们可以看到他们之间除了优先级, 其他的是都加载的, 是互补的关系(命令行带参spring.config.properties除外)
- 上面的测试, 除了删除之外, 改名也生效, 名字不是 application.properties/application.yml都不会认的;
- 我们没有试命令行指定某个参数, 比如
java -jar app.jar --server.port=8080
这个; 它是第一优先级!
8.3 官网说明
4.2.3. Application Property Files
SpringApplication
loads properties fromapplication.properties
files in the following locations and adds them to the SpringEnvironment
:
- A
/config
subdirectory of the current directory- The current directory
- A classpath
/config
package- 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:
file:./config/
file:./config/*/
file:./
classpath:/config/
classpath:/
8.4 加载优先级总结(按高到底:)
优先级高的会覆盖低的, 也可以理解他们的加载时机是顺序相反的!
启动时指定某些参数 >
java -jar app.jar --server.port=9999
启动时指定配置文件(有坑:互补失效!)
java -jar app.jar -spring.config.location=/mydir/application.properties
- jar同目录的config/application.properties
app.jar 同级别目录下的 ./config/application.properties
- jar同目录的application.properties
app.jar同级别目录下的 application.properties
- jar内部 classpath目录下的 ./config/application.properties
app.jar/BOOT-INF/classes/config/application.properties
jar内部classpath目录下的 application.properties
app.jar/BOOT-INF/classes/application.properties
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 hi@niewj.com