一、外部化配置
1、外部化配置资源类型
先来看看外部化配置的几种资源类型,除了 properties
和 YAML
外,还有环境变量、系统属性、启动参数等。所有的资源类型将近二十种,这里只介绍我们比较熟悉的:
- properties :这个应该都知道,就是在以
.properties
为后缀的文件中定义key value格式数据。 - YAML:文件格式是以
.yml
为后缀,文件中的数据也是key value格式,如下:
user:
name: rewind
age: 10
这里的key就是 user.name
、 user.age
。
- 环境变量:这是通过
System.getenv()
方式获取的默认配置,也是key value格式,下面列出部分配置,其它的还请自行了解,如下:
名称 | Key |
---|---|
Java安装目录 | JAVA_HOME |
classpath环境变量 | CLASSPATH |
用户临时文件目录 | TEMP |
计算机名 | COMPUTERNAME |
用户名 | USERNAME |
- 系统属性:这是通过
System.getProperties()
方式获取的默认配置,也是key value格式,下面列出部分配置,其它的还请自行了解,如下:
名称 | Key |
---|---|
运行时环境版本 | java.version Java |
Java安装目录 | java.home |
要使用的 JIT编译器的名称 | java.compiler |
操作系统的架构 | os.arch |
操作系统的版本 | os.version |
- 启动参数:一种是在
jar
包运行时行时传递的参数,如:java -jar xxx.jar name=张三 pwa=123
,还有一种是在 IDEA 的启动编辑配置的Program arguments
中输入数据:name=张三
可以看到,外部化配置中的数据都是key value 格式。这里还要注意它们的加载顺序,当key相同时,会出现覆盖的情况。
2、外部化配置的核心
首先来看取值方式,在 Spring
时代有 Environment
、 @Value
、 XML
三种方式,在 Spring Boot
时代则是 @ConfigurationProperties
方式。其中,涉及到了一个核心类,它就是 Environment
,该对象不仅可以获取所有的外部化配置数据,就连另外几种取值方式的数据来源也是从该类中获取。这里,主要对 Environment
和 @ConfigurationProperties
进行详细讨论, Environment
和 @ConfigurationProperties
是 Spring Boot
外部化配置的核心所在。
二、Environment
1、加载配置
public class SpringApplication {
...
public ConfigurableApplicationContext run(String... args) {
...
try {
...
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
...
}
...
}
在 SpringApplication
运行阶段的 run
方法中通过 prepareEnvironment
方法了创建 ConfigurableEnvironment
接口的实现类对象(该接口继承自 Environment
),ConfigurableEnvironment
是一个接口,且继承了 Environment
。进入创建方法:
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}