Spring Boot 应用终端日志乱码问题的完整解决方案

spring boot 应用在终端运行时出现日志乱码(如 `%.s.s.s.standardservicelr` 等异常字符),而在 intellij 中正常显示,根本原因是 jvm 默认字符编码与终端环境不匹配,需显式指定 `-dfile.encoding=utf-8` 启动参数。

该问题本质是 JVM 字符编码未对齐 导致的日志渲染异常。IntelliJ 默认以 UTF-8 启动 JVM,且其内置终端已正确配置编码;而系统终端(zsh/bash)启动 Java 进程时,JVM 会依据操作系统区域设置(locale)推断 file.encoding,若 locale 非 UTF-8(例如 en_US.ISO8859-1 或未正确配置),Spring Boot 的 ANSI 彩色日志、占位符解析及 Logback 日志格式化器将无法正确解码字节流,最终表现为大量 %.S.S.S... 类似乱码——这并非真实日志内容损坏,而是日志框架(如 Logback)在编码不一致时对 MDC、pattern layout 中的转义序列和样式标记(如 %clr, %5p, %logger)错误解析所致。

推荐解决方案(立即生效)
在终端中启动 JAR 包时,强制指定 UTF-8 编码:

java -Dfile.encoding=UTF-8 -jar target/app-0.001-SNAPSHOT.jar

进阶方案:全局或项目级固化配置

  • 方式 1:通过 JAVA_TOOL_OPTIONS(推荐,影响所有 java 命令)

    export JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF-8"
    # 加入 ~/.zshrc 或 ~/.bash_profile 永久生效
  • 方式 2:在 Maven 打包时嵌入 JVM 参数(适用于 CI/CD 或统一部署)
    在 pom.xml 的 spring-boot-maven-plugin 中配置:

    
      org.springframework.boot
      spring-boot-maven-plugin
      
        -Dfile.encoding=UTF-8
      
    
    ⚠️ 注意:此配置仅影响 mvn spring-boot:run,不影响 java -jar 直接运行。

验证是否生效
启动后检查日志首行是否含标准 Spring Boot Banner(带 ASCII 艺术字)及清晰时间戳、线程名、日志级别(如 INFO, DEBUG),而非 %.S.S.S...。也可在应用内添加测试代码确认当前编码:

System.out.println("Default charset: " + java.nio.charset.Charset.defaultCharset());
// 正常应输出:Default charset: UTF-8

? 额外建议

  • 确保终端本身支持 UTF-8:执行 locale 命令,确认 LANG 和 LC_ALL 均为 *.UTF-8(如 en_US.UTF-8)。若非 UTF-8,可临时设置:
    ex

    port LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8
  • 若使用 Docker,需在 Dockerfile 中同步设置:
    ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
    CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]

总结:该问题与 Spring Boot 版本、Shell 类型(zsh/bash)或 IDE 无关,纯粹是 JVM 启动时字符集协商失败所致。最简、最可靠的做法始终是显式传入 -Dfile.encoding=UTF-8 —— 它成本极低,兼容所有 Spring Boot 版本(2.x / 3.x),且是生产环境最佳实践之一。