【SpringBoot学习笔记 三】Profile多环境配置及配置优先级

上一篇Blog详细学习了YAML的语法、yml配置文件的编写以及SpringBoot是如何把配置文件自动绑定到代码中的,本篇Blog还是专注于讨论关于SpringBoot配置的事情,包括在真实的开发案例中,SpringBoot是如何进行多环境切换配置以及SpringBoot包含哪些配置文件,这些配置文件在绑定读取时又有哪些优先级。

Profile多环境配置

在实际的项目开发中,一个项目通常会存在多个环境,例如,开发环境、测试环境、预发环境以及生产环境等。不同环境的配置也不尽相同,例如开发环境使用的是开发数据库,测试环境使用的是测试数据库,而生产环境使用的是线上的正式数据库,Profile 为在不同环境下使用不同的配置提供了支持,我们可以通过激活、指定参数等方式快速切换环境

Profile配置方式

Spring Boot 的配置文件共有两种形式:.properties 文件和 .yml 文件,不管哪种形式,它们都能通过文件名的命名形式区分出不同的环境的配置,文件命名格式为:

application-{profile}.properties/yml

其中,{profile} 一般为各个环境的名称或简称,例如 dev、test 和 prod 等等,由于一般我们使用的配置文件是yml文件,所以这里只讨论yml文件的配置形式
【SpringBoot学习笔记 三】Profile多环境配置及配置优先级
我们可以添加 3 个配置文件,如下所示:

  • application-dev.yml:开发环境配置
  • application-test.yml:测试环境配置
  • application-prod.yml:生产环境配置

在 applcation.yml 文件中指定默认服务端口号为 8080,并通过以下配置来激活开发环境的 profile。

#默认配置
server:
  port: 8080
#切换配置
spring:
  profiles:
    active: dev #激活开发环境配置

在 application-dev.yml 中指定开发环境端口号为 8081,配置如下

#开发环境
server:
  port: 8081

在 application-test.yml 中指定测试环境端口号为 8082,配置如下

#测试环境
server:
  port: 8082

在 application-prod.yml 中指定生产环境端口号为 8083,配置如下

#生产环境
server:
  port: 8083

重启 Spring Boot 主程序,查看控制台输出,如下图:
【SpringBoot学习笔记 三】Profile多环境配置及配置优先级
通过上图可以看到,我们指定的开发环境(dev) Profile 生效了,且服务器端口为 8081

Profile激活方式

但是我们发现一个问题,就是每次切换环境还需要去配置里指定,然后通过修改dev为test或prod来切换项目环境 , 这样做的话每次切换环境都要重新改一下配置 , 而且如果不小心把本地改动提交到*仓库了 , 可能会影响到其他同事拉取代码,maven中提供了一个profile配置项,可以在打包时动态的指定环境配置.结合idea使用 , 我们可以实现不动任何代码来随意的切换我们的工作环境。

1 更改spring.profiles.active

首先我们修改原有的配置激活固定值为配置值:

spring.profiles.active=@env@

2 配置pom.xml

然后修改pom.xml,在其中加入一些profile信息:

<profiles>
        <!-- 开发环境 -->
        <profile>
            <id>dev</id>
            <properties>
                <env>dev</env><!-- 之前写的@env@就是通过这里的配置切换环境 -->
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault><!-- 指定缺省环境 -->
            </activation>
        </profile>
        <!-- 测试环境 -->
        <profile>
            <id>test</id>
            <properties>
                <env>test</env>
            </properties>
        </profile>
        <!-- 生产环境 -->
        <profile>
            <id>prod</id>
            <properties>
                <env>prod</env>
            </properties>
        </profile>
    </profiles>

3 切换Profile

修改完配置后,刷新下Maven面板我们就能在侧边看到Profiles的面板选项了,这个时候我们切换到prod然后重启服务器就可以看到生产环境的端口信息8083了。
【SpringBoot学习笔记 三】Profile多环境配置及配置优先级

SpringBoot配置加载顺序

Spring Boot 不仅可以通过配置文件进行配置,还可以通过环境变量、命令行参数等多种形式进行配置。这些配置都可以让开发人员在不修改任何代码的前提下,直接将一套 Spring Boot 应用程序在不同的环境中运行

Spring Boot 配置优先级

以下是常用的 Spring Boot 配置形式及其加载顺序(优先级由高到低):

  1. 命令行参数
  2. 来自 java:comp/env 的 JNDI 属性
  3. Java 系统属性(System.getProperties())
  4. 操作系统环境变量
  5. RandomValuePropertySource 配置的 random.* 属性值
  6. 配置文件(YAML 文件、Properties 文件)
  7. @Configuration 注解类上的 @PropertySource 指定的配置文件
  8. 通过 SpringApplication.setDefaultProperties 指定的默认属性

以上所有形式的配置都会被加载,当存在相同配置内容时,高优先级的配置会覆盖低优先级的配置;存在不同的配置内容时,高优先级和低优先级的配置内容取并集,共同生效,形成互补配置

配置文件加载顺序

通常情况下,Spring Boot 在启动时会将 resources 目录下的 application.propertiesapllication.yml 作为其默认配置文件,我们可以在该配置文件中对项目进行配置,但这并不意味着 Spring Boot 项目中只能存在一个 application.properties 或 application.yml,Spring Boot 项目中可以存在多个 application.propertiesapllication.yml

以上优先级中我们重点关注配置文件的加载顺序,这个是我们最常用的配置手段,Spring Boot 启动时,会自动加载 JAR 包内部及 JAR 包所在目录指定位置的配置文件(Properties 文件、YAML 文件),下图中展示了 Spring Boot 自动加载的配置文件的位置及其加载顺序,同一位置下,Properties 文件优先级高于 YAML 文件
【SpringBoot学习笔记 三】Profile多环境配置及配置优先级
上图中的节点说明如下:

  • /myBoot:表示 JAR 包所在目录,目录名称自定义;
  • /childDir:表示 JAR 包所在目录下 config 目录的子目录,目录名自定义;
  • JAR:表示 Spring Boot 项目打包生成的 JAR;
  • 其余带有“/”标识的目录的目录名称均不能修改。
  • 红色数字:表示该配置文件的优先级,数字越小优先级越高。

这些配置文件得优先级顺序,遵循以下规则:

  • 先加载 JAR 包外的配置文件,再加载 JAR 包内的配置文件;
  • 先加载 config 目录内的配置文件,再加载 config 目录外的配置文件;
  • 先加载 config 子目录下的配置文件,再加载 config 目录下的配置文件;
  • 先加载 appliction-{profile}.properties/yml,再加载 application.properties/yml
  • 先加载 .properties 文件,再加载 .yml 文件

我们做个实验
【SpringBoot学习笔记 三】Profile多环境配置及配置优先级
位于classpath:/config/下的配置文件内容为:

#类路径下的 config 目录下
#端口号为8084
#上下文路径为 /helloWorld
server:
  port: 8084
  servlet:
    context-path: /gcy

位于classpath:/下的配置文件内容为:

#默认配置
server:
  port: 8080

person:
  name: tml
  age: 30
  pets:
    -dog
    -cat
    -pig
  car:
    name: 蔚来es6
url:
  domain: www.baidu.com
  location: china

位于根目录下的配置文件为:

#项目根目录下
#上下文路径为 /tml
server:
  servlet:
    context-path: /tml

启动后发现启动信息为
【SpringBoot学习笔记 三】Profile多环境配置及配置优先级

根据 Spring Boot 默认配置文件优先级进行分析:

  • 该项目中存在多个默认配置文件,其中根目录下 /config 目录下的配置文件优先级最高,因此项目的上下文路径为 /tml
  • 类路径(classpath)下 config 目录下的配置文件优先级高于类路径下的配置文件,该项目的端口号为8084;

以上所有配置项形成互补,所以访问路径为http://localhost:8084/tml/hello
【SpringBoot学习笔记 三】Profile多环境配置及配置优先级
但是有一点需要注意,如果当前激活指定了spring.profiles.active: @env@某个配置文件,那么按照上述配置加载顺序走激活指定的Profile配置文件,如果不指定激活Profile,那么是不会加载appliction-{profile}.properties/yml配置文件,按照上述配置顺序加载appliction.properties/yml配置文件

总结一下

之前一直看不懂profile是干嘛的,现在终于知道了,是为了切换环境时使用不同配置身份用的,这个可比C#方便多了,记得之前拉代码的时候老会遇到配置被别人改到测试了,现在有了Maven的环境切换,方便多了,本地随便改。即使我们知道SpringBoot有这么多的配置优先级,其实实际用的时候我们也都是简单用,配置好启动身份后,我们一般只在类路径(classpath)下添加各个环境配置文件然后加载使用,避免混乱,但是大概了解下加载逻辑也便于之后方便排查问题。

上一篇:(十四)、SpringCloud Config分布式配置中心


下一篇:3 - 简单了解一下yml语法 和 使用yml赋值