第二十三章. YML 配置:环境隔离与 @ConfigurationProperties 注入
第二十三章. YML 配置:环境隔离与 @ConfigurationProperties 注入
Prorise第二十三章. YML 配置:环境隔离与 @ConfigurationProperties 注入
摘要:本章我们将深入 RVP 5.x 架构的“神经中枢”——YML 配置文件。我们将以 ruoyi-admin 模块为核心,分析主配置文件 application.yml 如何与环境配置 application-dev.yml 协作,并深入探讨 RVP 是如何通过“自动化加载”和“@ConfigurationProperties 注入”来管理整个框架的参数的。
本章学习路径

23.1. YML 语法与 application.yml 解析
在上一章中,我们深入解析了 RVP 5.x 的 Maven 架构,特别是根 pom.xml 如何通过 <profiles>(如 dev 和 prod)来定义构建环境。我们提到了 <profiles.active> 这个 Maven 变量。
但是,Maven 中定义的这个 dev 变量,Spring Boot 应用在“运行时”是如何感知到,并自动加载 application-dev.yml 文件的呢?
答案的起点,就在于主配置文件 application.yml。本节我们将从 YML 语法开始,逐步解析 RVP 主配置文件的核心机制。
23.1.1. YML 语法基础:层级、对象、数组
YML (YAML Ain’t Markup Language) 是一种常用于配置文件的序列化语言,它以“缩进”来表示层级关系。
1. 键值对(K-V)
YML 的核心是键值对。规范是“冒号 + 空格 + 值”。
1 | # 键: 值 (冒号后必须有空格) |
2. 对象(Object)server 节点本身就是一个对象,它包含了 port、servlet、undertow 等多个子属性。
1 | # 'server' 是一个对象 |
3. 数组(Array)
数组(或列表)通过“短横线 + 空格 + 值”来表示。
1 | # 'excludes' 是一个字符串数组 |
如果数组元素是对象,则可以混合使用:
1 | springdoc: |
23.1.2. application.yml (主配置) 结构总览
ruoyi-admin/src/main/resources/application.yml (源码文件 1) 是 RVP 的 主配置文件。
它的核心职责是定义 所有环境(local, dev, prod)都共享的默认配置。它包含了框架运行的基础参数,例如:
| 配置项 | 职责 |
|---|---|
server | 定义端口 8080、上下文路径 / 以及 undertow 容器参数。 |
captcha | 配置验证码的开关(enable: true)和类型(type: MATH)。 |
logging | 配置日志级别(@logging.level@)和 logback-plus.xml 的路径。 |
spring | 配置应用名、@profiles.active@、文件上传大小、Jackson 序列化等。 |
sa-token | 配置 Sa-Token 的 Token 名称、JWT 秘钥等。 |
security | 配置安全框架的全局放行路径(如 .html, .css)。 |
tenant | 配置多租户的开关(enable: true)和排除表。 |
mybatis-plus | 配置 Mapper 扫描路径、主键策略(ASSIGN_ID)。 |
springdoc | 配置 API 文档的分组信息。 |
23.1.3. 变量引用(一):@...@ (引用 pom.xml 中 profiles 的变量)
这是连接 Maven 构建环境和 Spring Boot 运行环境的“桥梁”。
在 application.yml 中,我们看到了 logging.level 和 spring.profiles.active 这两处特殊的配置:
1 | logging: |
@...@ 语法 不是 YML 的标准语法,也不是 Spring Boot 的语法,而是 Maven 资源过滤 的语法。
它与我们在上一章 22.4.4 节中分析的根 pom.xml 中的 <resources> 插件配置相对应:
- 根
pom.xml配置了<filtering>true</filtering>,要求 Maven 在构建时“过滤”application.yml文件。 - 当 Maven 在
dev环境下构建时(pom.xml中devprofile 被激活),它会读取devprofile 中定义的<properties>:1
2
3
4
5
6
7
8
9
10<profile>
<id>dev</id>
<properties>
<profiles.active>dev</profiles.active>
<logging.level>info</logging.level>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile> - Maven 会将
application.yml中的@profiles.active@替换为 静态字符串dev,将@logging.level@替换为info。 - 最终打包到
target/classes/application.yml的文件内容是:1
2
3spring:
profiles:
active: dev # [已替换] - Spring Boot 启动时,读取到
spring.profiles.active: dev,因此它知道需要 额外加载application-dev.yml。
23.1.4. 变量引用(二):${...} (引用 pom.xml 属性或 YML 内部变量)
${...} 语法是 Spring Boot 支持的标准占位符语法。它主要用于引用“运行时”的变量。
场景一:引用 pom.xml 中的属性 (来自 Maven)
在 application.yml 的 springdoc 配置中:
1 | springdoc: |
spring-boot-maven-plugin 会将 pom.xml 中的项目版本号(5.5.1)写入 META-INF,Spring Boot 启动时会读取该值,并替换 ${project.version}。
场景二:引用 YML 内部的其他变量 (来自 YML)
在 application-dev.yml 中,snail-job 的端口配置引用了主配置的 server.port:
1 | # 假设 application.yml (或 dev.yml) 中定义了 server.port |
这种方式常用于在 YML 内部保持配置的一致性。
23.1.5. 多文档分割 (---):配置隔离的实现
在 application.yml 的末尾,我们看到了 --- (三个短横线) 分隔符。
1 | # ... (上方 springdoc, xss 等配置) ... |
YML 规范中,同一个文件内的“顶级键”(如 spring, lock4j, management)理论上不应重复。
方案:--- 分隔符在 YML 中用于表示“一个新文档的开始”。Spring Boot 会 依次加载 同一个 application.yml 文件中被 --- 分隔的 所有文档,并将它们的配置进行 合并。
在 RVP 5.x 中,--- 的主要作用是“逻辑分组”。它将 lock4j、management、sse、websocket 等功能配置块进行清晰地分离,提高了配置文件的可读性。
23.2. 环境配置:application-dev.yml 与 application-prod.yml
在上一节中,我们深入分析了 application.yml 文件,并揭示了它内部最关键的一行配置:spring.profiles.active: @profiles.active@
我们知道,当使用 dev (开发) profile 构建时,这行配置会被 Maven 翻译为 spring.profiles.active: dev。本节我们将探讨当 Spring Boot 读取到这个 dev 值时,究竟会发生什么。
23.2.1. 环境配置的加载机制
Spring Boot 的配置文件加载机制具有“层级覆盖”的特性。
- 首先 (Phase 1):Spring Boot 总是 会加载
application.yml(主配置文件)。这会加载所有模块(server,sa-token,mybatis-plus等)的默认配置。 - 然后 (Phase 2):Spring Boot 检查
spring.profiles.active属性的值。 - 最后 (Phase 3):如果
spring.profiles.active的值是dev,Spring Boot 会 接着加载application-dev.yml文件。如果值是prod,则加载application-prod.yml。
[核心] 覆盖原则:如果在 application-dev.yml 中定义的配置项,与 application.yml 中的 完全相同(路径相同),那么 application-dev.yml 中的值将 覆盖 application.yml 中的值。
application.yml 定义了“通用默认值”,而 application-{profile}.yml 则定义了“特定环境的覆盖值”。
23.2.2. application-dev.yml 解析:覆盖“开发时”配置
ruoyi-admin/src/main/resources/application-dev.yml 的全部意义,就是用来覆盖那些在“开发环境”与“生产环境”中 必须不同 的配置。
我们来分析几个关键的“覆盖”示例:
1. 数据库 (spring.datasource)
application.yml:未定义 数据库 URL、用户名、密码。application-dev.yml:1
2
3
4
5
6
7
8
9spring:
datasource:
dynamic:
datasource:
# 主库数据源
master:
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&...
username: root
password: root- 分析:数据库连接信息是典型的环境相关配置。
application-dev.yml提供了本地开发时连接localhost数据库的凭证。
2. Redis (spring.data.redis)
application.yml:未定义 Redis 主机。application-dev.yml:1
2
3
4
5spring.data:
redis:
host: localhost
port: 6379
database: 0分析:提供了本地开发时连接
localhostRedis 的配置。
3. 监控中心 (spring.boot.admin.client)
application.yml:未定义 此配置。application-dev.yml:1
2
3
4
5spring.boot.admin.client:
enabled: true
url: http://localhost:9090/admin
username: @monitor.username@
password: @monitor.password@- 分析:在开发环境下,启用 Admin 客户端,并将其注册到位于
localhost:9090的监控中心。
4. 调度中心 (snail-job)
application.yml:未定义 此配置。application-dev.yml:1
2
3
4
5
6snail-job:
enabled: true
server:
host: 127.0.0.1
port: 17888
namespace: ${spring.profiles.active} # 引用 dev分析:在开发环境下,启用 SnailJob 客户端,并将其注册到位于
127.0.0.1的调度中心,且使用dev命名空间。
5. Actuator 敏感信息
application.yml:未定义 此配置(Spring Boot 默认NEVER,即隐藏)。application-dev.yml:1
2
3
4management:
endpoint:
env:
show-values: ALWAYS- 分析:这是一个关键的开发环境配置。它覆盖了 Spring Boot 的安全默认值,允许我们在 Admin 监控的“环境”页面查看所有配置属性(包括密码),极大地方便了开发调试,这是我们自己添加的
23.2.3. application-prod.yml 解析:覆盖“生产时”配置
application-prod.yml 则提供了生产环境的覆盖值。
我们以 justauth(三方授权)为例,对比 dev 和 prod 的差异:
application-dev.yml1
2
3
4
5
6justauth:
# 前端外网访问地址 (开发时通常是 http://localhost:81)
address: http://localhost:81
type:
gitee:
redirect-uri: ${justauth.address}/social-callback?source=giteeapplication-prod.yml(我们并未修改,若修改应该是如下的):1
2
3
4
5
6
7justauth:
# 生产环境必须是真实的公网域名
address: https://www.your-domain.com
type:
gitee:
# 回调地址也必须是公网域名
redirect-uri: ${justauth.address}/social-callback?source=gitee
分析:justauth.address 这个属性,在 dev 和 prod 环境中必须不同,因此它必须在 application-{profile}.yml 中被定义,而不是在 application.yml 中。
23.2.4. dev vs prod:日志级别 (logging.level) 的切换
最后,我们回到 23.1.3 节中的 logging.level 变量。
application.yml定义了日志级别:org.dromara: @logging.level@。- 当 Maven
devprofile 激活时,根pom.xml将@logging.level@替换为info。 - 当 Maven
prodprofile 激活时,根pom.xml将@logging.level@替换为warn。
结论:RVP 框架通过 Maven profiles 和 Spring Boot profiles 协同工作,实现了“一键切换”开发与生产环境的日志级别、数据库连接、Redis 连接、监控地址、调度地址等所有环境相关配置。
23.3. [核心] 插件化配置加载:@PropertySource
在 22.5 节分析 ruoyi-common-bom 时,我们看到 RVP 5.x 架构的核心是将 common 模块设计为“可插拔”的插件。这种插件化思想不仅体现在 Maven 依赖上,同样体现在 YML 配置上。
23.3.1. “非 application 开头”的 YML 加载痛点
我们首先要面对一个问题:Spring Boot 的自动配置机制,默认 只会 加载 classpath: 根目录下的 application.yml 和 application-{profile}.yml 文件。
然而,RVP 的 common 模块(如 ruoyi-common-mybatis)将自己的“内置配置”存放在了各自的 resources 目录下,例如 common-mybatis.yml 和 common-satoken.yml。
Spring Boot 不会 自动扫描并加载这些“非标”的 YML 文件。那么,RVP 是如何让这些插件化模块的配置生效的呢?
23.3.2. RVP 解决方案(一):@PropertySource 与 YmlPropertySourceFactory
RVP 框架利用了 Spring 的 @PropertySource 注解,并结合了一个自定义工厂 YmlPropertySourceFactory,来解决了这个问题。
@PropertySource:这是 Spring 框架提供的标准注解,用于 主动加载 指定路径的配置文件到 Spring 的“环境”(Environment) 中。YmlPropertySourceFactory:这是 RVP 在ruoyi-common-core中定义的一个工具类(源码文件ruoyi-common-core/.../factory/YmlPropertySourceFactory.java)。
为什么需要 YmlPropertySourceFactory?@PropertySource 注解在默认情况下,只支持解析 .properties 键值对格式,它 不认识 YML 的树状(缩进)语法。YmlPropertySourceFactory 的作用,就是“教会” @PropertySource 如何去解析 YML 文件。
23.3.3. 源码解析:MybatisPlusConfig.java 如何加载 common-mybatis.yml
ruoyi-common-mybatis 模块提供了一个完美的示例。我们来分析 MybatisPlusConfig.java :
1 | // 位于 ruoyi-common-mybatis/src/.../config/MybatisPlusConfig.java |
关键点分析:
@MapperScan("${mybatis-plus.mapperPackage}"):它从application.yml中读取mybatis-plus.mapperPackage属性(值为org.dromara.**.mapper)并扫描 Mapper。@PropertySource(...):value = "classpath:common-mybatis.yml":这行代码 强制 Spring 在启动时,去classpath下查找并加载common-mybatis.yml这个文件。factory = YmlPropertySourceFactory.class:指定使用 RVP 自定义的 YML 解析工厂来读取该文件。
配置合并与覆盖:通过这个注解,RVP 实现了配置的“分层管理”:
common-mybatis.yml(内置配置):存放了框架开发者预设的、不希望用户轻易修改的“最佳实践”配置。1
2
3
4
5
6
7
8
9# 源码文件 3 (common-mybatis.yml)
mybatis-plus:
configuration:
# 关闭 MyBatis 默认日志,统一使用 P6Spy
logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
global-config:
dbConfig:
# 逻辑已删除值
logicDeleteValue: 1application.yml(用户配置):存放了用户 应该 自定义的配置。1
2
3
4
5
6
7
8
9# 源码文件 1 (application.yml)
mybatis-plus:
# [用户配置]
mapperPackage: org.dromara.**.mapper
mapperLocations: classpath*:mapper/**/*Mapper.xml
global-config:
dbConfig:
# [用户配置]
idType: ASSIGN_ID
加载顺序与优先级:
Spring Boot 加载 application.yml 的优先级 高于 @PropertySource 加载的配置。
这意味着:
common-mybatis.yml中的logImpl配置会生效。application.yml中的idType: ASSIGN_ID会 覆盖common-mybatis.yml中定义的idType: ASSIGN_ID(虽然在此示例中它们的值相同)。- 最终,Spring 环境中会包含 两者合并 后的
mybatis-plus配置。
23.3.4. 源码解析:SaTokenConfig.java 如何加载 common-satoken.yml
RVP 框架中的 所有 ruoyi-common-* 插件都遵循此模式。例如 ruoyi-common-satoken 模块:
文件路径:ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java
1 | // 截取自 SaTokenConfig.java 源码 |
它使用完全相同的方式,加载了 common-satoken.yml,用于配置 Sa-Token 的 Token 前缀、超时时间等内置参数。
23.4. [核心] YML 属性注入:@ConfigurationProperties
在上一节中,我们分析了 RVP 框架如何使用 @PropertySource 将“非标” YML 文件(如 common-mybatis.yml)加载到 Spring 的“环境”(Environment) 中。
这种方式虽然解决了“加载”问题,但我们又遇到了一个新问题:在 Java 代码中如何 使用 这些配置值?
- 传统方式 (不推荐):在每个需要配置的类中,使用
@Value("${thread-pool.queue-capacity}")逐个注入。 - 痛点:这种方式非常繁琐,配置项分散在代码各处,缺乏类型安全(所有值都是字符串),且难以维护。
RVP 5.x 架构采用了 Spring Boot 推荐的最佳实践:@ConfigurationProperties,它将 YML 属性优雅地“注入”到类型安全的 Java Bean 中。
23.4.1. RVP 解决方案(二):从 YML 到 Java Bean 的映射
RVP 的配置注入分为两步:
- 定义 (Define):创建一个 POJO (Plain Old Java Object) 类,用
@ConfigurationProperties注解将其与 YML 中的一个“前缀”(prefix) 绑定。 - 激活 (Enable):在
AutoConfiguration类中,使用@EnableConfigurationProperties来“激活”这个 POJO 类,使其被 Spring 容器注册和填充。
我们以 ruoyi-common-core 模块中的线程池配置为例,深入解析这个过程。
23.4.2. 源码解析:ThreadPoolProperties.java (定义属性)
首先,开发者定义了一个 ThreadPoolProperties 类,用于 承载 thread-pool 命名空间下的所有 YML 属性。
文件路径:ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/properties/ThreadPoolProperties.java
1 | package org.dromara.common.core.config.properties; |
关键点分析:
@ConfigurationProperties(prefix = "thread-pool"):- [核心] 这个注解告诉 Spring Boot:“请在 YML 配置文件中查找所有以
thread-pool开头的配置项”。
- [核心] 这个注解告诉 Spring Boot:“请在 YML 配置文件中查找所有以
- 自动映射:
- Spring Boot 会自动将 YML 中的
kebab-case(短横线命名, 如queue-capacity) 映射到 Java 类的camelCase(驼峰命名, 如queueCapacity) 字段上。 - 它还会自动进行 类型转换,将 YML 中的字符串(如
10)转换为 Java 中的int或boolean类型。
- Spring Boot 会自动将 YML 中的
@Data(Lombok):自动生成getter/setter方法,这是@ConfigurationProperties注入所必需的。
23.4.3. 源码解析:ThreadPoolConfig.java (激活属性)
仅仅定义 ThreadPoolProperties 类是不够的,Spring Boot 不会自动扫描它。我们必须在配置类中 显式激活 它。
文件路径:ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java
1 | package org.dromara.common.core.config; |
关键点分析:
@AutoConfiguration:表示这是一个 Spring Boot 自动配置类。RVP 的common模块通过告诉 Spring Boot 启动时自动加载这个ThreadPoolConfig。@EnableConfigurationProperties(ThreadPoolProperties.class):- [核心] 这个注解是“激活器”。它告诉 Spring 容器:“请立即创建
ThreadPoolProperties.java这个类的 Bean 实例,并根据@ConfigurationProperties(prefix = "thread-pool")注解,从 YML 中读 1 取属性来填充它。”
- [核心] 这个注解是“激活器”。它告诉 Spring 容器:“请立即创建
最终流程:
- RVP 启动,Spring Boot 加载
ThreadPoolConfig(因为@AutoConfiguration)。 @EnableConfigurationProperties被触发,Spring 创建ThreadPoolPropertiesBean。- Spring Boot 从
application.yml和application-dev.yml等文件中,找到thread-pool前缀下的所有属性。 - Spring Boot 将
queue-capacity: 200(YML) 注入到ThreadPoolPropertiesBean 的queueCapacity(Java) 字段中。 ThreadPoolConfig内部就可以直接@Autowired或通过方法参数注入这个 已填充完毕 的ThreadPoolPropertiesBean,并使用它来配置线程池。
23.5. [实战] 二次开发:添加自定义配置
在 23.3 和 23.4 节中,我们已经系统性地分析了 RVP 框架加载和注入配置的两种核心机制:@PropertySource 和 @ConfigurationProperties。现在,我们将把这些理论知识应用到“二次开发”的实战中,为 RVP 框架添加一个全新的“微信小程序”配置模块。
23.5.1. 目标:为新模块 mini-app 添加 appid 和 secret 配置
我们的目标是,在 YML 文件中添加一个新的配置块 mini-app,用于存放小程序的 appid 和 secret,并使 RVP 框架能够像加载 ThreadPoolProperties 一样,将这些配置自动注入到一个类型安全的 Java Bean 中,供业务代码使用。
23.5.2. 步骤一:在 application-dev.yml 中定义 mini-app 属性
首先,我们选择开发环境配置文件 application-dev.yml 来添加我们的新配置。
文件路径:ruoyi-admin/src/main/resources/application-dev.yml
我们打开此文,在文件末尾添加 --- 分隔符和我们新的 mini-app 配置块:
1 | # ... (justauth 等其他配置) ... |
---:使用多文档分隔符,保持配置的逻辑隔离。mini-app:定义了我们配置的“前缀”(prefix),必须使用kebab-case(短横线命名法)。appid/secret:我们自定义的属性。
23.5.3. 步骤二:创建 MiniAppProperties.java (使用 @ConfigurationProperties)
接下来,我们创建 Java Bean 来“承载”这些 YML 属性。在 RVP 5.x 架构中,最佳实践是将这种配置类放在对应模块的 config/properties 包下。我们以 ruoyi-demo 模块为例:
文件路径:ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/config/properties/MiniAppProperties.java
我们创建这个新文件,并添加 @ConfigurationProperties 注解:
1 | package org.dromara.demo.config.properties; |
@ConfigurationProperties(prefix = "mini-app"):
[核心] 将此类与 YML 中mini-app前缀的配置项进行绑定。- 字段映射:Spring Boot 会自动将 YML 中的
appid映射到 Java 字段appid,将secret映射到secret。 @Data:Lombok 注解,自动生成getter/setter,这是属性注入所必需的。
23.5.4. 步骤三:创建 MiniAppConfig.java (使用 @EnableConfigurationProperties 激活)
我们已经定义了 Properties 类,现在需要一个配置类来“激活”它,让 Spring Boot 容器去创建并填充这个 Bean。
文件路径:ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/config/MiniAppConfig.java
我们创建这个新的 AutoConfiguration 类:
1 | package org.dromara.demo.config; |
@AutoConfiguration:声明这是一个 Spring Boot 自动配置类。@EnableConfigurationProperties(MiniAppProperties.class):
[核心] 这个注解是“激活器”。它告诉 Spring Boot:“请启用MiniAppProperties这个配置类,并立即根据其@ConfigurationProperties注解去 YML 加载属性来填充它。”
23.5.5. 步骤四:在 Service 中注入并使用 MiniAppProperties
完成以上三步并 重启服务 后,MiniAppProperties Bean 就已经注册到 Spring 容器中,并被填充了 YML 中的 appid 和 secret 值。
我们可以在任何其他 Bean(如 Service, Controller)中 直接注入 并使用它:
1 | // 示例:在 ruoyi-demo 模块的某个 Service 中使用 |
@RequiredArgsConstructor:Lombok 注解,自动生成一个包含final字段(miniAppProperties)的构造函数,Spring Boot 会自动通过这个构造函数完成注入。miniAppProperties.getAppid():此时获取到的值,就是我们在application-dev.yml中配置的wx123456789abcdef。
23.5.6. YML 多行文本(|)的用法
最后,我们补充一个 YML 语法:如何配置换行的多行文本。
如果我们的 mini-app 配置中有一个 info 字段,需要包含换行符:
YML 配置:
1 | mini-app: |
|(Literal Block Scalar):YML 语法中的“字面量块”。它告诉解析器,保留intro:字段 下方所有缩进 的文本,并且 保持它们的换行符。
Java 注入结果:
1 |
|
miniAppProperties.getInfo()的值是:"信息第一行\n信息第二行"miniAppMProperties.getIntro()的值是:"这是多行信息\n第二行\n第三行\n"









