参考资料:
Sprinb Boot 2.1.5.RELEASE 官方文档Spring framework 5.1.9.RELEASE 官方文档
配置中心以 Spring Cloud Config 作为展开
前置问题
在以Spring Boot 和 Spring Cloud 作为技术栈的开发中,针对应用的配置最常见用的就是三种配置,
- classpath 下的 application.properties
- commandline-args :命令行参数,通过 java命令启动应用时指定的入参
- 以及分布式系统中的分布式配置中心
假设此时:在这三个配置中,同时存在一个配置:ext-info=XX 。那么 在程序运行时,究竟那么配置会生效?
先来看看 Spring Boot 提供外部化配置
Externalized Configuration
Spring Boot lets you externalize your configuration so that you can work with the same application code in different environments.You can use properties files, YAML files, environment variables, and command-line arguments to externalize configuration.Property values can be injected directly into your beans by using the
@Value
annotation, accessed through Spring’sEnvironment
abstraction, or be bound to structured objects through@ConfigurationProperties
.
大意如下:
为了使得同一套代码,能够在不同的配置环境下运行, Spring Boot 提供了多种配置外部化的能力,同时这几种配置方式能够共存。
这几种外部化配置存在的形式,包括 properties 文件、YML 文件、环境变量、命令行参数等。
在程序中,开发者可以通过 @Value 注解,直接引用 Environment 对象,或者通过 @ConfigurationProperties注解等方式对这些外部化配置进行读取,灵活的变更程序配置。
配置信息分布在不同位置不同文件中,使得配置更灵活,但必然会带来一个问题:不同配置文件中存在同一个属性配置(如:ext-info=XXX),应用程序在运行中会以哪个配置文件的配置作为其运行配置?
针对这个问题,Spring Boot 官方给出了说明文档,在多种配置文件共存的情况下,应用程序会选择哪个配置文件的属性配置作为运行配置(读取优先级:由高到低)
- Devtools global settings properties on your home directory (
~/.spring-boot-devtools.properties
when devtools is active). @TestPropertySource
annotations on your tests.properties
attribute on your tests. Available on@SpringBootTest
and the test annotations for testing a particular slice of your application.- Command line arguments.
- Properties from
SPRING_APPLICATION_JSON
(inline JSON embedded in an environment variable or system property). ServletConfig
init parameters.ServletContext
init parameters.- JNDI attributes from
java:comp/env
. - Java System properties (
System.getProperties()
). - OS environment variables.
- A
RandomValuePropertySource
that has properties only inrandom.*
. - Profile-specific application properties outside of your packaged jar (
application-{profile}.properties
and YAML variants). - Profile-specific application properties packaged inside your jar (
application-{profile}.properties
and YAML variants). - Application properties outside of your packaged jar (
application.properties
and YAML variants). - Application properties packaged inside your jar (
application.properties
and YAML variants). @PropertySource
annotations on your@Configuration
classes.- Default properties (specified by setting
SpringApplication.setDefaultProperties
).
实例测试其中几种常见配置方式的优先级顺序
测试的配置方式如下
- 优先级 4 的 Command line arguments :命令行参数配置
- 优先级 12 的 jar包外部的 application.properties
- 优先级 13 的 jar 包内部的 application.properties(默认:classpath 下的 application.properties)
一、环境准备
-
运行环境
spring Boot 2.1.5.RELEASE Web 应用 -
准备测试的属性配置
ext-info=XXX -
提供 API,用来读取 ext-info 配置信息
@Value("${ext-info}") private String extInfo; /** http://localhost:9527/ext-info **/ @RequestMapping("/ext-info") public String extInfo(){ return extInfo; }
-
通过 /actuator/env 端点,获取当前应用存在的多种配置文件信息
二、优先级测试
测试一、 【优先级 4 】Command line arguments(命令行配置) VS 【优先级 13 】application.properties(jar 包内部默认配置文件)
-
**step1、**在 jar 包内部,src/main/resource 中的 application.properties 文件中增加测试配置 主要配置
# 内部配置文件 ext-info = info-inside-jar
-
**step2、**运行 jar 程序,同时指定命令行参数 –ext-info=commandLineArgs
java -jar ext-configuration-0.0.1-SNAPSHOT.jar --ext-info=commandLineArgs
-
**step3、**访问 自定义API、和 actuator env 端点
- 自定义 API 访问 curl “http://localhost:9527/ext-info”
结果:commandLineArgs - actuator env 端点
- 自定义 API 访问 curl “http://localhost:9527/ext-info”
-
结论
Command line arguments(命令行配置) 配置属性优先级比 **application.properties(jar 包内部默认配置文件)**高,两者存在同一个属性配置时,以 Command line arguments(命令行配置) 配置为主。
测试二、 【优先级 13】 application.properties(jar 包内部默认配置文件)VS【优先级 12】 application-outside.properteis(jar包外部配置文件)配置 优先级
-
**step1、**外部配置文件 application-outside.properties 主要配置
# 外部配置文件 ext-info = outside-jar
在 运行 jar 程序时,通过命令行参数的方式指定外部配置文件 –spring.config.location=XXX
-
**step2、**jar 包内配置文件 application.properteis 主要配置(同测试一)
# 内部配置文件 ext-info = info-inside-jar
-
**step3、**运行 jar 程序
java -jar ext-configuration-0.0.1-SNAPSHOT.jar --spring.config.location=.xxxxx/application-outside.properties -
**step4、**访问 自定义API、和 actuator env 端点
- 自定义 API 访问 curl “http://localhost:9527/ext-info”
结果:outside-jar - actuator env 端点
- 自定义 API 访问 curl “http://localhost:9527/ext-info”
-
结论
application-outside.properteis(jar包外部配置文件) 配置属性读取优先级比 application.properties(jar 包内部默认配置文件) 高。两者存在同一配置属性时,以外部配置文件的属性配置为主。命令行指定了外部配置文件:jar包内的 application.properties 以及 bootstrap.properties 文件将不再被加载
测试三、【优先级 4 】 Command line arguments(命令行配置)、【优先级 13】application.properties(jar 包内部默认配置文件) 、【优先级12】 application-outside.properteis(jar包外部配置文件)配置 优先级
这里不进行测试流程展示,通过测试一和测试二能够得出,三者的优先级由高到低依次为:Command line arguments(命令行配置) > application-outside.properteis(jar包外部配置文件) > application.properties(jar 包内部默认配置文件)
更多内容,参考官方文档
源码分析:Command line arguments(命令行配置)和 内部配置文件 为例,分析 Spring Boot 如何实现配置读取的优先级。
前置概念
分析之前,先来看看 Spring Boot 应用的环境上下文 Environment。引用Spring Framework 官方对于 Environemtn 的说明:
The
Environment
interface is an abstraction integrated in the container that models two key aspects of the application environment: