1、前言
在某些SpringBoot项目中,有时会看到在配置文件中使用 ${xxx} 取值的情况,但是这些 xxx 变量在哪里进行设置呢?比如下面的端口号使用server.port=${PORT} 。

2、官网说明
在Spring官网上有针对性的介绍:Core Features (spring.io) ,下面是官网上列出的15中设置外部属性配置的方式。

上图列出了有15中方式设置外部属性变量的方式,从上到下优先级依此增加(即:如果通过多种方式设置了同一个外部属性变量,则后面设置的值会覆盖前面的)。本篇博客主要介绍上图中标记的6中方式,这6种设置方式也是实际工作中最为常用的方式。介绍的方向是:
(1)如何通过不同的方式设置外部的属性变量;
(2)通过实验体现优先级的效果。
3、几种设置方式
为了进行实验,首先要新建一个最普通的SpringBoot项目。此处说明一些内容,开始我使用的是SpringBoot 2.5.0 (配合jdk1.8)版本,在测试过程中发现此版本并不是按照官网给定的优先级去查找外部配置信息(可能此版本有BUG),然后我换了高版本的SpringBoot 3.3.4 (JDK也要换成17)再测试,发现优先级加载正确了。所以如果你的项目使用的是较低版本的SpringBoot,可能会存在一些问题。
项目的pom文件如下:
<?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>3.3.4</version>
<relativePath/>
</parent>
<groupId>com.shg</groupId>
<artifactId>Externalized_configuration</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Externalized_configuration</name>
<description>Externalized_configuration</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
项目的目录结构如下:

3.1、默认设置的属性变量
在项目的启动类中,通过设置默认的属性变量的方式如下:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.HashMap;
import java.util.Map;
@SpringBootApplication
public class ExternalizedConfigurationApplication {
public static void main(String[] args) {
// SpringApplication.run(ExternalizedConfigurationApplication.class, args);
SpringApplication app = new SpringApplication(ExternalizedConfigurationApplication.class);
Map<String, Object> defaultProperties = new HashMap<>();
defaultProperties.put("PORT", 8081);
app.setDefaultProperties(defaultProperties);
app.run(args);
}
}
在项目的 application.properties 配置文件中使用如下方式取得变量PORT的值,如下:
server.port=${PORT}
启动项目,发现项目的端口号是8081

3.2、通过@PropertySource设置的属性变量
在项目的resources目录下,新建一个port.properties属性文件,然后在其中配置变量信息:
PORT=8082
在 标注有 @Configurations的配置类上,通过@PropertySource引入外部的配置文件,因为主启动类也是一个标注了@Configuration的配置类,所以就直接在主启动类上标注如下信息:
@PropertySource(value = {"classpath:port.properties"})
启动项目(注意:保留之前启动类里面的8081配置),发现端口号变成了8082,这就说明高优先级的配置信息覆盖了低优先级的配置。即:3.2优先级覆盖了上面的3.1优先级 
3.3、通过配置文件设置的属性变量
在项目的配置文件application.properties文件里面配置PORT=8083。注意:此处我们暂不讨论一个项目中同时存在application.properties和application.yml这两种配置文件的情况。此处我们先假设项目中使用的只有一种配置文件:application.properties,其中的配置信息如下:
启动项目(注意:保留之前启动类里面的8081配置和port.properties里面的8082配置信息),发现端口号变成了8083,说明3.3的优先级覆盖了上面的3.2优先级。如下图:

3.4、操作系统环境变量
此处要注意:操作系统环境变量有两种设置方式。
(1)Windows系统通过 <高级系统设置> - <环境变量> 进行设置,如下图:

再次重启项目,发现端口号还是8083。这不是Spring的问题,而是我们需要重启IDEA,加载我们刚刚设置的 操作系统环境变量。重启IDEA后,再次启动项目,发现端口号已经变成了8084,说明3.4的优先级覆盖了上面的3.3优先级。如下图:

(2)通过IDEA进行设置系统环境变量。
上面是通过操作系统的环境变量进行设置的外部属性和值(想一想你的JAVA_HOME环境变量),还可以通过IDEA设置系统环境变量。设置方式如下图:

启动项目,发现端口号已经变成了8085,这也说明3.4的优先级覆盖了上面的3.3优先级。如下图:

上述两种设置系统环境变量的方式,其中第一种是永久设置,全局有效(即:本机器上的任何SpringBoot项目都可以通过 server.port=${PORT} 取到8084的值);第二种设置方式只针对当前SpringBoot项目有效。
3.5、Java 系统属性(JVM环境变量)
Java系统属性可以通过IDEA进行设置,如下图,通过-DPORT=8086进行设置:

重启项目(注意:保留之前的所有配置),发现端口号已经变成了8086,说明3.5的优先级覆盖了上面的3.4优先级。

3.6、命令行设置的参数变量
通常SpringBoot项目会打成jar包,通过 java -jar xxx.jar 的方式进行启动。在使用这种方式启动时,可以指定一些外部配置信息,比如此处的端口号。
项目打包成 xxx.jar后,直接通过命令行进行启动,如下:

启动时,指定端口号,如下:
java -jar -DPORT=8087 externalized_configuration-0.0.1-SNAPSHOT.jar
发现端口号已经变成了8087,说明3.6的优先级覆盖了3.5的优先级。
4. 总结
优先级就是按照上面的 3.1 ~ 3 .6 依此递增的。大白话解释就是如果程序启动时先在
(1)3.6 命令行里面找到端口号,如果找到了就直接用。如果没找到,就去
(2)3.5 中的 Java系统属性里面找,看看是否配置了属性名为 PORT的环境变量信息,如果找到了,就直接用,如果没找到,就去
(3)3.4 中的操作系统环境变量里面找是否配置了属性名为 PORT 的环境变量信息,如果找到了就直接用,如果没找到,就去
(4)3.3 中的配置文件里面找是否配置了 PORT 的环境变量信息,如果找到了就直接用,如果没找到,就去
(5)3.2 中的 有@PropertySource指定的外部配置文件找是否配置了 PORT 的环境变量信息,如果找到了就直接用,如果没找到,就去
(6)3.1 中的 启动时设置的默认端口号,如果找到了就直接用,如果没找到,就使用默认的8080端口号。
817

被折叠的 条评论
为什么被折叠?



