当前位置: 首页 > java >正文

Spring Boot配置中YAML文档结构的理解

摘要

本文探讨了YAML文档结构对Spring Boot应用程序配置加载的影响。特别关注了文档分隔符(---)、特定环境配置与配置属性解析之间的交互关系。研究表明,配置属性相对于文档分隔符的不当放置可能导致意外的应用程序行为,本文以JWT配置为例进行了具体分析。

1. 引言

Spring Boot提供了强大的配置机制,支持多种格式,包括YAML。YAML的层次结构便于组织配置管理,特别是对于跨多个环境部署的应用程序。然而,YAML的文档分隔符语法与Spring Boot的特定环境配置加载机制之间的微妙交互可能导致不易察觉的问题。

本研究论文探讨了这种交互的具体表现:属性放置位置相对于文档分隔符对Spring Boot应用程序配置加载行为的影响。

2. YAML文档结构与Spring Boot配置

2.1 YAML文档分隔符

在YAML中,三个连字符的分隔符(---)用于在单个文件中划分不同的文档。Spring Boot利用这一特性在统一的配置文件中定义特定环境的配置。

2.2 Spring Boot特定环境配置

Spring Boot允许通过spring.config.activate.on-profile属性(在Spring Boot 2.4.0及以后版本中)或spring.profiles属性(在早期版本中)进行特定环境配置。当某个环境被激活时,Spring Boot会在默认配置的基础上应用相应的特定环境配置。

3. 配置加载行为

3.1 加载顺序

Spring Boot按以下顺序加载配置属性:

  1. 默认属性(未与任何特定环境关联的属性)
  2. 特定环境属性(针对激活的环境)

在每个类别中,属性按照其来源的优先级顺序加载。

3.2 YAML文件中的文档关联

Spring Boot中YAML配置的一个关键方面是属性如何与文档关联。**在文档分隔符之后定义的属性与该分隔符引入的文档相关联。**如果某个文档通过spring.config.activate.on-profile指定了一个环境,则该文档中的所有属性都被视为该环境特有的配置。

4. 案例研究:JWT配置

4.1 问题描述

考虑一个在application.yml中配置了JWT认证的Spring Boot应用程序。以下配置结构导致在使用dev环境运行时无法访问JWT属性:

# 默认配置
server:port: 8080servlet:context-path: /apispring:application:name: rbac-adminprofiles:active: dev# ... 其他默认配置 ...---
# 开发环境配置
spring:config:activate:on-profile: dev
springdoc:api-docs:enabled: true---
# 测试环境配置
spring:config:activate:on-profile: test
# ... 测试环境特有属性 ...---
# 生产环境配置
spring:config:activate:on-profile: prod
springdoc:api-docs:enabled: false# JWT配置(放在最后一个文档分隔符之后)
jwt:secret: secret_key_1234567890_abcdefg_123456_09898787access-token-expiration: 1800000refresh-token-expiration: 604800000token-prefix: "Bearer "header-string: "Authorization"issuer: tttt

4.2 分析

在上述配置中,JWT属性放置在最后一个文档分隔符之后,该分隔符引入了生产环境配置。因此,这些JWT属性隐式地与生产环境(prod)相关联。当应用程序以dev环境运行时,这些属性不会被加载。

4.3 解决方案

4.3.1 将JWT属性移至默认配置

将JWT属性移至默认配置部分(任何文档分隔符之前)可确保无论激活哪个环境,这些属性都会被加载:

# 默认配置
server:port: 8080servlet:context-path: /api# JWT配置(放在默认配置中)
jwt:secret: secret_key_1234567890_abcdefg_123456_paradeaccess-token-expiration: 1800000refresh-token-expiration: 604800000token-prefix: "Bearer "header-string: "Authorization"issuer: paradespring:application:name: rbac-adminprofiles:active: dev# ... 其他默认配置 ...---
# 开发环境配置
spring:config:activate:on-profile: dev
# ... 开发环境特有属性 ...
4.3.2 在各环境中复制JWT属性

另一种方法是,如果需要环境特定的值,可以在每个环境特定部分中复制JWT属性:

# 默认配置
server:port: 8080# ... 其他默认属性 ...---
# 开发环境配置
spring:config:activate:on-profile: dev
# ... 开发环境特有属性 ...# 开发环境的JWT配置
jwt:secret: dev_secret_keyaccess-token-expiration: 1800000# ... 其他JWT属性 ...---
# 生产环境配置
spring:config:activate:on-profile: prod
# ... 生产环境特有属性 ...# 生产环境的JWT配置
jwt:secret: prod_secret_keyaccess-token-expiration: 3600000# ... 其他JWT属性 ...
4.3.3 使用独立的JWT配置文件

为了更好地组织,可以将JWT配置提取到单独的文件中:

# application-jwt.yml
jwt:secret: secret_key_1234567890_abcdefg_123456_paradeaccess-token-expiration: 1800000refresh-token-expiration: 604800000token-prefix: "Bearer "header-string: "Authorization"issuer: parade

然后在主配置中包含这个文件:

# application.yml
spring:profiles:active: dev#include多个使用,分隔include: jwt

5. 实证验证

对假设的行为进行了实证验证:

  1. 观察到当JWT配置放在生产环境文档分隔符之后时,不会被加载
  2. 确认当JWT配置移至默认配置部分时,成功加载
  3. 验证特定环境部分中的JWT配置在相应环境激活时正确加载

6. 结论和最佳实践

6.1 主要发现

  1. YAML文档分隔符之后定义的属性与该文档中指定的环境相关联
  2. 适用于所有环境的属性应放在默认配置部分(任何文档分隔符之前)
  3. 特定环境的属性应明确放在相应的环境特定文档中

6.2 推荐的最佳实践

  1. 明确结构:在YAML配置文件中保持清晰明确的结构,默认属性在开头,特定环境属性在明确标记的部分
  2. 完整文档:确保每个特定环境的文档都是完整的,包含所有相关属性
  3. 通用属性:将所有环境通用的属性放在默认部分

6.3 实施指南

以下是Spring Boot应用程序YAML配置文件的推荐结构:

# 默认配置(适用于所有环境)
common-property1: value1
common-property2: value2spring:application:name: application-name# ... 其他通用属性 ...---
# 开发环境配置
spring:config:activate:on-profile: devdev-specific-property: value---
# 测试环境配置
spring:config:activate:on-profile: testtest-specific-property: value---
# 生产环境配置
spring:config:activate:on-profile: prodprod-specific-property: value

参考文献

  1. Spring Boot文档. (2023). 外部化配置. https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config
  2. YAML 1.2规范. (2009). YAML不是标记语言. https://yaml.org/spec/1.2/spec.html
  3. Spring框架文档. (2023). Bean定义环境. https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-definition-profiles
http://www.xdnf.cn/news/2393.html

相关文章:

  • Nacos-SpringBoot 配置无法自动刷新问题排查
  • React自定义Hook之useMutilpleRef
  • CD33.【C++ Dev】初识模版
  • 深度学习4.1 多层感知机
  • 基础的贝叶斯神经网络(BNN)回归
  • 【C++详解】C++入门(二)引用、内联函数、nullptr宏
  • 23种设计模式-行为型模式之备忘录模式(Java版本)
  • MSO-Player:基于vlc的Unity直播流播放器,支持主流RTSP、RTMP、HTTP等常见格式
  • Python包的编译、构建与打包指南
  • 解析 OpenHarmony、HarmonyOS 与 HarmonyOS Next:优雅草卓伊凡的观点
  • AI医疗革命:DeepMind CEO展望十年内攻克疾病难题
  • 权力结构下的人才价值重构:从 “工具论” 到 “存在论” 的转变​
  • 《深入浅出Git:从版本控制原理到高效协作实战》​
  • AOSP Android14 Launcher3——Launcher的状态介绍LauncherState类
  • 文章记单词 | 第49篇(六级)
  • 20250427 对话1: 何东山的宇宙起源理论
  • Java学习-Java基础
  • JavaEE-多线程实战01
  • VScode在 Markdown 编辑器中预览
  • err: Error: Request failed with status code 400
  • 大模型——Spring.new快速构建AI驱动的定制化商业应用
  • 在线教育系统开发常见问题及解决方案:源码部署到运营维护
  • 关系型数据库PostgreSQL for Mac 保姆级使用教程
  • iOS自定义电池电量显示控件 BatteryView 实现
  • 【Java】分布式事务解决方案
  • 【Axure高保真原型】3级多选下拉列表
  • 统信操作系统使用默认yum源安装 Docker 的踩坑
  • 基于 Playwright 构建小型分布式爬虫(进阶版)
  • 关于指针和指针算术
  • [论文梳理] 足式机器人规划控制流程 - 接触碰撞的控制 - 模型误差 - 自动驾驶车的安全合规(4个课堂讨论问题)