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

解决Spring Boot启动时YAML配置占位符导致的ScannerException(yml占位符动态替换)

前言

在Spring Boot项目中,YAML配置文件常使用占位符(如 @logging.level@)实现动态配置。然而,若未正确配置Maven资源过滤机制,占位符可能未被替换,导致ScannerException


一、问题现象与报错分析

1.1 报错信息

ERROR org.springframework.boot.SpringApplication -- Application run failed  
org.yaml.snakeyaml.scanner.ScannerException: while scanning for the next token  
found character '@' that cannot start any token. (Do not use @ for indentation)  
in 'reader', line 14, column 19:  
        com.xiaoli: @logging.level@  
                      ^  

1.2 错误定位

  1. 错误类型ScannerException表明YAML解析器在读取配置文件时遇到非法字符。
  2. 关键线索
    • 错误位置指向@logging.level@,说明占位符未被替换。
    • Do not use @ for indentation提示YAML语法中@不可作为标识符开头。
  3. 根本原因
    • Maven构建时未正确替换YAML文件中的占位符,导致残留的@...@符号被YAML解析器识别为非法字符。

二、解决方案与配置解析

2.1 核心思路

通过 Maven资源过滤机制,在构建过程中动态替换YAML文件中的占位符(如${logging.level}),确保最终输出的配置文件不含未解析的占位符。

2.2 配置详解

pom.xml中,通过<resources>标签配置资源过滤规则:

<build>  
    <resources>  
        <!-- 第一个resource:复制所有资源,但关闭过滤 -->  
        <resource>  
            <directory>src/main/resources</directory>  
            <filtering>false</filtering>  
        </resource>  
        <!-- 第二个resource:仅对指定文件启用过滤 -->  
        <resource>  
            <directory>src/main/resources</directory>  
            <filtering>true</filtering>  
            <includes>  
                <include>application*</include>  
                <include>bootstrap*</include>  
                <include>banner*</include>  
            </includes>  
        </resource>  
    </resources>  
</build>  
2.2.1 配置作用解析
  1. 第一个 <resource>

    • <directory>:指定资源目录为src/main/resources
    • <filtering>false</filtering>:关闭过滤功能,确保所有文件(包括未使用占位符的文件)被直接复制到构建输出目录(如target/classes)。
    • 作用:避免因过滤导致某些资源文件被遗漏。
  2. 第二个 <resource>

    • <directory>:仍指向src/main/resources,但通过<includes>限制范围。
    • <includes>:仅包含以applicationbootstrapbanner开头的文件(如application.ymlbootstrap.properties)。
    • <filtering>true</filtering>:启用过滤功能,替换文件中的占位符(如${logging.level})。
    • 作用:对目标文件进行占位符替换,同时避免对其他文件重复操作。
2.2.2 关键点说明
  • 资源覆盖机制
    Maven会按顺序处理资源块:
    1. 第一个块将所有文件(未过滤)复制到输出目录。
    2. 第二个块再次复制指定文件(已过滤),覆盖未过滤的版本,确保最终文件为已替换的版本。
  • 占位符格式
    Maven默认使用${...}格式的占位符,而非@...@。若需使用其他符号(如@...@),需通过<configuration>自定义占位符语法(复杂度较高,建议采用标准格式)。

三、扩展知识点与最佳实践

3.1 YAML语法规范

  1. 除了我们这种动态替换的场景,不要用@符号
    • YAML中@不可作为标识符开头,其常用于注释或特殊语法(如@start)。
    • 示例错误
      key: @value@  # 非法,YAML解析器无法识别  
      
  2. 正确缩进与冒号
    • 使用2个空格缩进,避免制表符(Tab)。
    • 键值对后需加空格,如key: value而非key:value

3.2 Maven资源过滤机制

  1. 过滤流程
    • Maven读取pom.xml中的<properties><profiles>定义的属性值。
    • 在构建时,替换资源文件中${属性名}为实际值。
  2. 属性定义示例
    <properties>  
        <logging.level>debug</logging.level>  
    </properties>  
    
  3. 环境配置
    <profiles>  
        <profile>  
            <id>dev</id>  
            <properties>  
                <logging.level>debug</logging.level>  
            </properties>  
        </profile>  
        <profile>  
            <id>prod</id>  
            <properties>  
                <logging.level>info</logging.level>  
            </properties>  
        </profile>  
    </profiles>  
    

3.3 验证配置有效性

  1. 清理并构建
    mvn clean install -Pdev  # 指定dev环境  
    
  2. 检查输出文件
    • 进入target/classes目录,确认application.yml中的占位符已被替换为实际值(如debug)。
  3. 日志验证
    • 启动应用后,查看日志是否包含logging.level的生效信息。

四、常见问题与排查建议

4.1 问题:占位符未被替换

  • 原因
    • 未在pom.xml中定义属性值。
    • 文件未被包含在<includes>中。
  • 解决
    1. 检查<properties><profiles>中是否定义了对应属性。
    2. 确保文件名匹配<include>规则(如application.yml需匹配application*)。

4.2 问题:资源文件缺失

  • 原因
    • 第一个<resource>块未关闭过滤,导致部分文件未被复制。
  • 解决
    • 确保第一个<resource>块的<filtering>设置为false

五、总结

5.1 核心知识点回顾

  1. Maven资源过滤:通过<resources>配置动态替换占位符。
  2. YAML语法规范:避免使用@符号,严格遵循缩进与格式。
  3. 环境配置管理:通过<profiles>实现多环境属性切换。

5.2 知识点延伸

  • 进阶配置
    • 使用<excludes>排除特定文件。
    • 通过<filter>指定额外的过滤属性文件。
  • 工具辅助
    • 使用IDEA的Maven插件实时检查资源过滤配置。
    • 使用yamllint工具验证YAML文件格式。

六、完整配置示例

<project>  
    <!-- 其他配置省略 -->  
    <build>  
        <resources>  
            <resource>  
                <directory>src/main/resources</directory>  
                <filtering>false</filtering>  
            </resource>  
            <resource>  
                <directory>src/main/resources</directory>  
                <filtering>true</filtering>  
                <includes>  
                    <include>application*.yml</include>  
                    <include>bootstrap*.properties</include>  
                </includes>  
            </resource>  
        </resources>  
        <properties>  
            <logging.level>debug</logging.level>  
        </properties>  
        <profiles>  
            <profile>  
                <id>prod</id>  
                <properties>  
                    <logging.level>info</logging.level>  
                </properties>  
            </profile>  
        </profiles>  
    </build>  
</project>  

相关文章:

  • android 14.0 工厂模式 测试音频的一些问题(高通)
  • 【AGI-Eval行业动态】OpenAI 语音模型三连发,AI 语音进入“声优”时代
  • Redisson 实现分布式锁
  • Flask返回文件方法详解
  • 急速实现Anaconda/Miniforge虚拟环境的克隆和迁移
  • SpringCloud微服务(一)Eureka+Nacos
  • ADGaussian:用于自动驾驶的多模态输入泛化GS方法
  • AI与大数据融合:技术全景、行业实践与前沿趋势(2025版)
  • Python监控网站更新则推送到企业微信
  • 生产事故:Undertow容器的xnio线程引发CPU100%的方案验证后续(二)
  • Spring MVC与Spring Boot文件上传配置差异对比及文件上传关键类详细说明与对比
  • 【小沐杂货铺】基于Three.JS绘制太阳系Solar System(GIS 、WebGL、vue、react,提供全部源代码)
  • 谈Linux之磁盘管理——万字详解
  • CMDB平台(进阶篇):机房拓扑功能深度解析
  • css使用mix-blend-mode的值difference实现内容和父节点反色
  • redis的数据类型(1)
  • 12、主频和时钟配置实验
  • PhotoShop学习06
  • SpringBoot学生评奖评优管理系统的设计与实现
  • SpringBoot3笔记
  • 佛山网站建设专业主修课程/百度关键词查询工具免费
  • 写出网站版面布局设计步骤/手机网页链接制作
  • 男女裸体直接做的视频网站/网络营销策划的目的
  • 网站外链 快速建设/页面设计漂亮的网站
  • 前端做任务的网站/自媒体人专用网站
  • 如何做游戏推广网站/友情链接是外链吗