Spring Boot v2.4.4源码解析(五)配置文件加载上 —— 2.4版本与2.3版本差异

本文主要是介绍Spring Boot v2.4.4源码解析(五)配置文件加载上 —— 2.4版本与2.3版本差异,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Spring Boot 2.4版本与2.3版本处理配置文件差异

一、概述

从Spring Boot v2.4.4源码解析(三)事件机制篇一这篇博客中可以看出,在Spring Boot启动过程中包含很多关键时间节点,EventPublishingRunListener会将这些时间节点封装成事件并通过SimpleApplicationEventMulticaster广播出去。
在这些时间节点中,有一个environmentPrepared,表示环境已经准备好,如果需要对环境做定制化操作的组件,可以监听该事件。Spring Boot正是在该时间节点将配置文件加载到环境EnvironmentpropertySources属性中。

在事件广播器SimpleApplicationEventMulticaster 广播事件方法multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) 内部打断点,断点条件是event instanceof org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent,表示发布ApplicationEnvironmentPreparedEvent事件时进入断点。
在这里插入图片描述
然后在Variables中添加getApplicationListeners(event, type)查看有哪些事件监听器监听ApplicationEnvironmentPreparedEvent事件。
在Spring Boot 2.3版本和2.4版本中会发现有如下ApplicationEnvironmentPreparedEvent事件监听器:

二、变更原因

注意,2.3版本中ConfigFileApplicationListener和2.4版本中EnvironmentPostProcessorApplicationListener正是处理配置文件的事件监听器。
为什么Spring Boot 2.4版本要放弃ConfigFileApplicationListener而使用EnvironmentPostProcessorApplicationListener处理配置文件加载呢?

Config file processing in Spring Boot 2.4这篇博客给出了答案。

总结主要原因如下:
  • 支持Kubernetes卷挂载配置;
    卷挂载配置是 Kubernetes 的一个流行功能,其中ConfigMap可以将环境配置信息和容器镜像解耦便于应用配置的修改。
    这块内容可以参考K8s 集群使用 ConfigMap 优雅加载 Spring Boot 配置文件。
  • ConfigFileApplicationListener本身存在一些问题;
    在Config file processing in Spring Boot 2.4文章中, 作者将ConfigFileApplicationListener 比喻为陷阱冒险(trap adventures),并不是指其代码质量不高,或者测试覆盖不全面,而是指很难添加新功能。
    在处理特定profile配置文件(主要YAML文件)会遇到两个问题:
    • 可以在这些配置文件中激活附加的profiles;
    • 很难弄清楚配置文件的添加顺序;

例如,在YAML文件中可以包含多个逻辑文件,这些逻辑文件之间用---分隔开。考虑如下包含三个逻辑文件的YAML文件:

security.user.password: usera
---
spring.profiles: local
security.user.password: userb
runlocal: true
---
spring.profiles: prod
spring.profiles.include: local
security.user.password: userc

在Spring Boot 2.3中添加VM参数-Dspring.profiles.active=prod并启动,获取security.user.passwordrunlocal配置,会发现其值分别为userbtrue。是不是感觉有点奇怪,在处理中间文件时,该文件的profiles还未被激活,但是最终该文件还是被包含进来了。
所以在Spring Boot 2.4中对加载properties和YAML配置文件方式作出了两个重大改变,旨在简化和合理化加载外部配置的方式:

  • 将按照定义顺序加载文件;
  • 不能在特定profile文件中激活profiles;

三、主要变更点

1. YAML 多逻辑文件顺序变更

对于Spring Boot 2.3及更早版本, YAML中的多个逻辑文件基于profile激活顺序添加,而在2.4版本中,则按照文件声明顺序添加。
例如,对于如下YAML文件:

test: "value"
---
test: "overridden-value"

最终test属性值为overridden-value

2. 增加 Properties 文件多逻辑文件

在 Spring Boot 2.4 中,在Java properties文件中可以使用和YAML类似的多逻辑文件,多个逻辑文件之间用#---隔开。
例如:

test=value
#---
test=overridden-value

3. Jar 包外部配置文件和内部配置文件顺序变更

在Spring Boot 2.3及更早版本中,Jar包外部的application.properties文件不会覆盖Jar包内部的application-<profile>.properties文件。
从Spring Boot 2.4开始,外部文件总是覆盖Jar包内部文件(application-<profile>.properties文件或者其他文件);
具体配置文件加载顺序可以参考Application properties outside of jar should take precedence over profile-specific variants inside the jar,Spring Boot Reference Documentation 2.3.6.RELEASE,Spring Boot Reference Documentation 2.4.1。

Spring Boot 2.3及更早版本配置文件优先级(从上到下优先级降低):

  • Jar包外部的application-{profile}.properties文件及application-{profile}.yml
  • Jar包内部的application-{profile}.properties文件及application-{profile}.yml
  • Jar包外部的application.propertiesapplication.yml;
  • Jar包内部的application.propertiesapplication.yml;

Spring Boot 2.4配置文件优先级(从上到下优先级降低):

  • Jar包外部的application-{profile}.properties文件及application-{profile}.yml
  • Jar包外部的application.propertiesapplication.yml;
  • Jar包内部的application-{profile}.properties文件及application-{profile}.yml
  • Jar包内部的application.propertiesapplication.yml;

4. spring.profiles 配置项迁移

在Spring Boot 2.3及更早版本中,可以在YAML的多逻辑文件中使用spring.profiles指定该配置文件生效的profile,在2.4版本中,将该配置项迁移到spring.config.activate.on-profile

5. Profile 激活

Spring Boot中可以使用spring.profiles.active配置项激活特定的profiles,例如可以使用如下命令行激活prod

$ java -jar myapp.jar --spring.profiles.active=prod

当然也可以在application.properties或者application.yaml文件中配置该配置项,但是在Spring Boot 2.4中,不能在特定profile文件中设置该配置项值。也就是说,在Spring Boot 2.4中,配置项spring.config.activate.on-profilespring.profiles.active不能同时设置。类似地,配置项spring.config.activate.on-profilespring.profiles.include也不能同时设置。
例如,如下配置将会报错:

spring:config:activate:on-profile: "prod"profiles:include: "metrics"

为什么会增加这样一个限制呢?
加了这个限制后,同一个文件中on-profile条件只会计算一次,前文这个问题就会解决。

6. Profile 组

由于Spring Boot 2.4不能同时设置spring.config.activate.on-profilespring.profiles.active,也不能同时设置spring.config.activate.on-profilespring.profiles.include,那对于2.3版本使用spring.profiles + spring.profiles.include扩展激活profiles这种情况怎么兼容呢?
例如,如下application.yaml

spring.profiles: "debug"
spring.profiles.include: "debugdb,debugcloud"

如果迁移到Spring Boot 2.4 application.yaml变更为:

spring:config:activate:on-profile: "debug"profiles:include: "debugdb,debugcloud"

但是不能同时设置spring.config.activate.on-profilespring.profiles.include
为了解决这类问题,Spring Boot 2.4 提出Profile组概念,Profile组可以完成这样一件事:如果profile 'x’处于激活状态,profiles ‘y’ 和 ‘z’ 也处于激活状态。配置项格式为spring.profiles.group.<source>,例如,上面的配置可以这样写:

spring:profiles:group:"debug": "debugdb,debugcloud"

同样,也不能同时设置配置项spring.profile.groupspring.config.activate.on-profile的值。

7. 导入附加配置

配置文件加载成功后,会以OriginTrackedMapPropertySource形式存在EnvironmentPropertySources属性中。可以在Spring Boot启动类中增加如下代码,查看引入了哪些配置文件:

ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
propertySources.forEach( s -> {if(s instanceof OriginTrackedMapPropertySource){System.err.println(s);}
});

在Spring Boot 2.3版本中,配置文件默认搜索顺序为(从上到下优先级降低):

  • file:./config/
  • file:./config/*/
  • file:./
  • classpath:/config/
  • classpath:/

在Jar包内部resources目录,Jar包内部resources/config目录,Jar包当前目录,Jar包当前/config目录,Jar包当前/config/fsx目录下面分别放置application.yml,然后以java -jar target/demo-0.0.1-SNAPSHOT.jar命令行运行该Jar包,会发现如下输出:

OriginTrackedMapPropertySource {name='applicationConfig: [file:./config/application.yml]'}
OriginTrackedMapPropertySource {name='applicationConfig: [config/fsx/application.yml]'}
OriginTrackedMapPropertySource {name='applicationConfig: [file:./application.yml]'}
OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/config/application.yml]'}
OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.yml]'}

搜索配置文件名称默认为application,可以通过配置项spring.config.name配置,也可以使用配置项spring.config.location明确指定配置文件搜索顺序(多个文件或者目录质检用逗号隔开)。
例如,以命令行java -jar target/demo-0.0.1-SNAPSHOT.jar --spring.config.location=classpath:/,file:./ 启动时,输出如下:

OriginTrackedMapPropertySource {name='applicationConfig: [file:./application.yml]'}
OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.yml]'}

可以通过spring.config.additional-location在默认的搜索顺序上增加搜索路径,该配置项的值优先默认的搜索顺序。
在Jar包路径/custom-config目录下添加application.yml文件,并以命令行java -jar target/demo-0.0.1-SNAPSHOT.jar --spring.config.additional-location=file:./custom-config启动时,输出如下:

OriginTrackedMapPropertySource {name='applicationConfig: [file:custom-config/application.yml]'}
OriginTrackedMapPropertySource {name='applicationConfig: [file:./config/application.yml]'}
OriginTrackedMapPropertySource {name='applicationConfig: [config/fsx/application.yml]'}
OriginTrackedMapPropertySource {name='applicationConfig: [file:./application.yml]'}
OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/config/application.yml]'}
OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.yml]'}

此时,配置文件默认搜索顺序为(从上到下优先级降低):

  • file:./custom-config/
  • classpath:custom-config/
  • file:./config/
  • file:./config/*/
  • file:./
  • classpath:/config/
  • classpath:/

但有一个问题,这几个配置项必须配置为环境属性,例如操作系统环境变量,系统变量,命令行参数,不能中application.properties或者 application.yml中指定,且文件名仅限于.properties, .yaml, 或者.yml
在Spring Boot 2.4 中新增了配置项spring.config.import,可以使用该配置项导入附加配置, 且该配置项可以在application.properties或者 application.yml中设置,导入文件添加顺序在定义该配置项文件之后。

8. 卷挂载配置树

如果使用spring.config.import导入附加配置时,该配置项的值没有前缀,就认为导入常规文件或者文件夹,如果以configtree作为前缀,则告诉Spring Boot该路径为Kubernetes风格的卷加载配置树。
例如,在application.properties中定义如下配置项:

spring.config.import=configtree:/etc/config

如果有如下挂载内容:

etc/+- config/+- my/|  +- application+- test

那么,最终会在Environment中增加两个属性:my.applicationtest,其值分别为/etc/config/my/application/etc/config/test

9. 云平台激活

如果只想卷挂载配置树在指定的云平台下才激活,可以使用spring.config.activate.on-cloud-platform配置。该配置和spring.config.activate.on-profile相似,只不过使用的是云平台的值,而非profile名称。

例如,上面配置只在Kubernetes下部署才生效,可以如下配置

spring.config.activate.on-cloud-platform=kubernetes
spring.config.import=configtree:/etc/config

10. 第三方配置源

配置项spring.config.import的值完全是可拔插的,我们可以自定义扩展。可以想象第三方Jar来支持诸如archaius://...vault://...zookeeper://...之类的配置路径。
这部分源码可以参考org.springframework.boot.context.config包下的ConfigDataLocationResolverConfigDataLoader类。

11. 仍然使用Spring Boot 2.3配置方式

如果Spring Boot 2.4这种变更让你很不爽,想在Spring Boot 2.4 下使用原有配置文件加载方式, 可以在application.properties或者 application.yml文件中将配置项spring.config.use-legacy-processing置为true,那么Spring Boot将沿用2.3版本方式处理配置文件。
Spring Boot版本迁移时,一些配置项的变更可能对我们造成困惑,我们可以在pom文件中引入spring-boot-properties-migrator模块,引入后在项目启动时,当你的配置文件中存在被识别的已经移除的属性时,将会日志打印提示。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-properties-migrator</artifactId><scope>runtime</scope>
</dependency>

版本迁移完成后,再将该模块从pom文件中移除。

参考

  • [1] Config file processing in Spring Boot 2.4
  • [2] Application properties outside of jar should take precedence over profile-specific variants inside the jar
  • [3] Spring Boot Reference Documentation 2.3.6.RELEASE
  • [4] Spring Boot Reference Documentation 2.4.1
  • [5] Including profiles in spring boot 2.4.0 version

这篇关于Spring Boot v2.4.4源码解析(五)配置文件加载上 —— 2.4版本与2.3版本差异的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/965860

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听