🚀 外服游戏 / Github / Google 加速 💰 20 刀/年的海外服务器 🐟 外出摸鱼
首页›教程›Spring Boot 配置文件从 properti…

Spring Boot 配置文件从 properties 迁移到 yaml:步骤与常见坑

发布于 2026-10-20ToYaml.com约 5 分钟读完

把 Spring Boot 的 application.properties 迁移到 application.yml,核心就是三件事:点号分隔的层级改成缩进,a[0]=x 改成 - x,多环境文件合并成用 --- 分隔的多文档。真正容易出问题的不是语法转换,而是迁移之后的行为差异:properties 优先级更高、YAML 会改变值的类型、@PropertySource 读不了 yml、含特殊字符的值要加引号。下面按步骤走一遍,每个坑都附了我在 Spring Boot 3.5.7 上的实测结果。

一、迁移前先确认三件事

  1. Spring Boot 版本。多环境写法在 2.4 前后不一样:2.4 之前用 spring.profiles 给文档指定环境,2.4 起改为 spring.config.activate.on-profile。你的版本决定了第三步怎么写。
  2. 有没有代码在直接读配置文件。全局搜索 @PropertySource、Properties.load、ClassPathResource("application。通过 Spring 环境读取(@Value、@ConfigurationProperties、Environment)的不受影响,直接读文件的会出问题。
  3. 备份并确保能回滚。最简单的做法是先提交一次 git,迁移作为独立提交,出问题 git revert 即可。

二、第一步:用工具转换,再人工整理

假设现有的 application.properties 是这样的:

server.port=8081
server.servlet.context-path=/api
spring.application.name=demo-service
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=Abc@123
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
logging.level.root=info
logging.level.com.example.demo=debug
app.cors.allowed-origins[0]=https://a.example.com
app.cors.allowed-origins[1]=https://b.example.com
app.feature.enabled=true
app.welcome=Hello World

打开 ToYaml.com 的 Properties ⇄ YAML 转换器,把内容粘贴到左边,点 to yaml。转换结果在结构上是正确的,但有两点要手动处理:一是转换器输出的键按字母顺序排列(app 在最前,spring 在后面),和你原来的阅读习惯不同;二是 logging.level.com.example.demo 会被拆成 com → example → demo 三层嵌套,写起来啰嗦。整理之后的版本:

server:
  port: 8081
  servlet:
    context-path: /api
spring:
  application:
    name: demo-service
  datasource:
    url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: Abc@123
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
logging:
  level:
    root: info
    com.example.demo: debug
app:
  cors:
    allowed-origins:
      - https://a.example.com
      - https://b.example.com
  feature:
    enabled: true
  welcome: Hello World

我用 Spring Boot 的加载器把这两份文件分别展开,15 个属性的键和值逐项一致。注意 JDBC 地址里有 :、?、&,但它们后面都不跟空格,所以 YAML 里不用加引号;只有出现 ": "(冒号加空格)或 " #"(空格加井号)时才必须加。

三、第二步:核对写法对应关系

PropertiesYAML说明
a.b.c=1a: → b: → c: 1每个点号对应一层缩进(2 个空格)
list[0]=xlist: 下 - x下标变成 -,顺序即下标
list[0].name=a- name: a对象列表,同一个元素的属性要缩进对齐
hosts=a,b,chosts: a,b,c 或写成列表绑定到 List<String> 时两种都行
key=(空值)key: 或 key: ''Spring Boot 中读到的都是空字符串
# 注释# 注释写法相同

对象列表是最容易写错缩进的地方。看一个对照:

app.servers[0].name=a
app.servers[0].port=1
app.servers[1].name=b
app.servers[1].port=2
app:
  servers:
    - name: a
      port: 1
    - name: b
      port: 2

要点:- name: a 里的 name 和下一行的 port 必须左对齐(- 后面的空格也算缩进)。我试过把 - a 下一行的 - b 多缩进一个空格,结果两个元素被悄悄合并成了一个字符串 "a - b",没有任何报错,所以列表写完要数一数元素个数。

四、第三步:多环境配置

迁移前常见的结构是 application.properties 加 application-dev.properties、application-prod.properties。迁移到 YAML 有两种做法,都可以用。

做法一:保持多文件,只改后缀

application-dev.yml 和 application-prod.yml 与 application.yml 并列。我用 application.yml 写 app.name: base、application-dev.yml 写 app.name: dev-file,以 --spring.profiles.active=dev 启动,读到的是 dev-file。这种方式改动最小,团队成员最容易接受。

做法二:一个文件多文档

用 --- 把不同环境写在同一个 application.yml 里。Spring Boot 2.4 及以上这样写:

app:
  name: base
  note: shared
---
spring:
  config:
    activate:
      on-profile: dev
app:
  name: dev-name
---
spring:
  config:
    activate:
      on-profile: prod
app:
  name: prod-name

实测结果:不指定环境时 app.name 是 base;--spring.profiles.active=dev 时是 dev-name,app.note 仍然继承自第一段的 shared;指定 prod 时是 prod-name。第一个文档(没有 on-profile)是所有环境共享的默认值。

老写法在新版本里会直接启动失败。如果你照着老教程写 spring.profiles: dev,在 Spring Boot 2.4.2 上我实测只会打一行 WARN,并且仍按老逻辑生效;但在 Spring Boot 3.5.7 上,应用启动时直接抛出异常:

org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property 'spring.profiles' imported from location 'file [application.yml]' is invalid and should be replaced with 'spring.config.activate.on-profile' [origin: URL [file:application.yml] - 5:13]

把 spring.profiles 全部替换成 spring.config.activate.on-profile 即可。

如果某些文件暂时保留 properties

properties 文件也能做多文档:用单独一行 #--- 分隔。我在 Spring Boot 3.5.7 和 2.4.2 上都验证过下面的写法,激活 dev 时 app.name 是 dev-name,不激活时是 base:

app.name=base
#---
spring.config.activate.on-profile=dev
app.name=dev-name

用在线转换器把多文档 YAML 转成 properties 时要留意:转换器会把所有文档合并成一个文件,app.name=base 和 app.name=dev-name 依次出现,后一个会覆盖前一个。这种情况请手动拆开,或者保留 yml 格式。

五、第四步:删除旧文件,别让两份配置共存

迁移完成后务必把 application.properties 删掉(或至少移出 classpath)。原因前面提过:同目录下 properties 优先于 yml,旧文件里的值会悄悄覆盖新文件,表现为"改了 yml 不生效"。我的复现:properties 里 app.name=from-properties,yml 里 app.name: from-yml,最终读到 from-properties。同时存在时,没有冲突的键还会合并,这会掩盖遗漏——你以为迁完了,其实有些配置还在读旧文件。

六、第五步:验证迁移结果

最可靠的办法是"转回去对比":把迁移后的 yml 再用转换器的 to prop 转成 properties,然后和原文件排序后比较。保存为 back.properties 之后:

diff <(grep -v '^#' application.properties | sort) <(grep -v '^#' back.properties | sort) && echo SAME

我用上面第二节的 15 行样例做了一遍,输出 SAME,说明键和值都没丢。注意转换器会丢弃注释和空行,所以比较时先过滤掉注释。另外需要确认的是类型:下一节列的几类值,转换器不一定替你处理。

七、迁移后的常见坑

1. 值被当成别的类型

YAML 会把 yes、no、on、off 解析为布尔值,把以 0 开头的数字当成八进制(001234 读成 668),把 12:30 当成六十进制整数(读成 750),3.10 读成浮点数 3.1。这些在 properties 里都只是字符串。解决办法是给这类值加引号。详细清单见 YAML 常见语法错误排查。

2. 特殊字符开头的值

以 @、*、%、! 或反引号开头的值,YAML 里必须加引号。最常见的是 Maven 资源过滤:spring-boot-starter-parent 默认用 @ 作为占位符分隔符,所以 properties 里的 app.version=@project.version@ 迁移到 YAML 后必须写成 version: '@project.version@'。不加引号的话,Spring Boot 报错:

found character '@' that cannot start any token. (Do not use @ for indentation)
 in 'reader', line 2, column 9:
      mail: @company.com
            ^

3. @PropertySource 读不了 yml

这是迁移时最隐蔽的坑。@PropertySource("classpath:extra.yml") 不会报错,但它按 properties 语法解析 yml:缩进的子键被当成顶层键。我用下面的 yml 实测:

app:
  extra: hello
server:
  port: 9090

用 @Value("${app.extra:NOT_FOUND}") 读取得到的是 NOT_FOUND,而不带前缀的 @Value("${extra:NOT_FOUND}") 反而读到了 hello。解决办法是自己提供一个 PropertySourceFactory:

import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import java.io.IOException;
import java.util.Properties;

public class YamlPropertySourceFactory implements PropertySourceFactory {
    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
        factory.setResources(resource.getResource());
        Properties props = factory.getObject();
        return new PropertiesPropertySource(
                name != null ? name : resource.getResource().getFilename(), props);
    }
}

使用时写 @PropertySource(value = "classpath:extra.yml", factory = YamlPropertySourceFactory.class)。我编译运行过这个类,app.extra 能正确读到 hello。如果只是想加载额外的配置文件,更推荐 Spring Boot 2.4+ 的 spring.config.import=classpath:extra.yml,它走的是和 application.yml 相同的加载器。

4. 键名写法与绑定

@ConfigurationProperties 支持宽松绑定。我在类里声明 maxPoolSize 字段,分别在配置文件里写 app.max-pool-size、app.maxPoolSize、app.max_pool_size,三种写法都绑定成功;用环境变量 APP_MAXPOOLSIZE 或 APP_MAX_POOL_SIZE 也能覆盖,命令行 --app.max-pool-size=23 同样有效。但 @Value 就严格得多:配置里写 app.max-pool-size 时,@Value("${app.max-pool-size}") 能取到,而 ${app.maxPoolSize} 和 ${app.max_pool_size} 都取不到。所以文件里统一用小写加连字符(kebab-case),既是官方推荐,也能避开 @Value 的坑。

5. 同名列表整体替换

多处配置了同一个列表时,不会逐项合并,而是优先级高的整体替换。实测 yml 里 app.hosts 有 a、b、c 三项,properties 里只写 app.hosts[0]=x,最终结果是只有 x。迁移期如果新旧文件并存,这类问题很难发现。

6. 反斜杠与中文

properties 里 C:\temp\new 会被解析成 Tab 加换行,必须写成 C:\\temp\\new;YAML 的普通写法里反斜杠不转义,C:\temp\new 原样保留(但在双引号字符串里反斜杠会被当作转义,我试过 "C:\temp\x" 会直接报 expected escape sequence of 2 hexadecimal numbers,用单引号或不加引号即可)。中文方面,迁移到 YAML 后可以直接写汉字,不再需要 \uXXXX 转义——Spring Boot 读 properties 按 ISO-8859-1,而读 YAML 按 UTF-8。

八、迁移清单

  1. 确认 Spring Boot 版本,决定多环境写法。
  2. 用转换器生成 yml,按阅读习惯调整顺序。
  3. 检查数字样字符串(版本号、邮编、工号)、yes/no/on/off、@ 开头的值,必要时加引号。
  4. 多环境配置改成多文件或多文档,把 spring.profiles 换成 spring.config.activate.on-profile。
  5. 检查 @PropertySource,yml 文件要么换 spring.config.import,要么提供自定义工厂。
  6. 删除旧的 properties,转换回 properties 做排序 diff。
  7. 在测试环境启动一次,确认各环境的关键配置值(端口、数据源、开关)符合预期。

想进一步了解两种格式的差别可以看 YAML 和 Properties 有什么区别;转换前后如果想看看 YAML 对应的 JSON 结构,用 YAML ⇄ JSON 工具。

读完就动手试试:粘贴你的配置,一键转换并检查结果。

相关文章
YAML 和 Properties 有什么区别?怎么选语法对照表、Spring Boot 优先级、类型陷阱、中文编码,以及什么时候该选哪种。 YAML 常见语法错误排查:缩进、冒号、特殊字符、Tab真实报错原文 + 修法:Tab、冒号、引号、重复 key,以及不报错却改了值的类型陷阱。
更多工具
Properties ⇄ YAMLProperties 与 YAML 在线互转 YAML ⇄ JSONYAML 与 JSON 在线互转 JSON 格式化 / 校验格式化、压缩 JSON,语法错误提示行号 Unix 时间戳转换时间戳与日期时间互转,支持毫秒 Base64 编码 / 解码支持中文 UTF-8 的 Base64 互转 URL 编码 / 解码URL 参数编解码,支持中文 Crontab 表达式解析解析定时表达式,预测最近执行时间 我的 IP 查询查看当前公网出口 IP,一键复制