Spring Boot 启动报错 "Username must not be null"?你可能混淆了这两个 Profile 配置

前言

最近在启动一个 Spring Boot 3.x 项目时,遇到了一个看似莫名其妙的错误:

Factory method \u0027esbRestClient\u0027 threw exception with message: Username must not be null

明明 esb-config.yml 里写得好好的 username 和 password,为什么 Spring 说它们是 null?更诡异的是,这段代码昨天还能跑,今天就不行了?

经过一番排查,发现了一个非常容易踩的 Spring Boot Profile 配置坑。写下来分享给大家。

问题复现

项目结构是一个多模块 Maven 项目,application.yml 长这样:

# application.yml
spring:
  application:
    name: hr-expand-sync-server
  config:
    import:
      - classpath:esb-config.yml
      - classpath:dlp-config.yml
      - classpath:xxl-job-config.yml
    activate:
      on-profile: dev
server:
  port: 25001

esb-config.yml 是这样的:

# esb-config.yml
esb:
  server-host: http://esbprd.jasolar.com:8011
  username: \u0027hsp_xxx\u0027
  password: \u0027xxxxxxx\u0027

按说配置很清晰,启动 mvn spring-boot:run -pl hr-expand-sync-server 时却报错:

The following 1 profile is active: "default"
...
Username must not be null

根因分析

两个神似但截然不同的配置

这里的关键在于区分 Spring Boot 中两个名字里都有 "profile" 的配置:

配置项 角色 本质
spring.profiles.active 激活器 告诉 Spring:"我要用 dev 这个profile"
spring.config.activate.on-profile 过滤器 告诉 Spring:"我这段配置只在 dev 下才生效"

前者是一把开关,后者是一道滤网

问题就在这里

上面的 application.yml 中写的是:

spring:
  config:
    activate:
      on-profile: dev

它的意思是:这段配置(包括 config import)只在 dev profile 已激活 的前提下才加载。

但是——没有任何地方去激活 dev profile

所以实际运行时,Spring 使用的默认 profile default,而 spring.config.activate.on-profile: dev 这个过滤器发现当前不是 dev,直接把整个 import 操作跳过了。于是 esb-config.ymldlp-config.ymlxxl-job-config.yml 全部没有被加载,所有配置值都是 null。

修复方案

修复极其简单——加上一行 spring.profiles.active: dev

# application.yml ✅ 修复后
spring:
  application:
    name: hr-expand-sync-server
  profiles:
    active: dev               # ← 激活 dev profile
  config:
    import:
      - classpath:esb-config.yml
      - classpath:dlp-config.yml
      - classpath:xxl-job-config.yml

server:
  port: 25001

启动日志验证:

The following 1 profile is active: "dev"
...
Started HrExpandSyncApplication in 1.435 seconds

深度理解

spring.config.activate.on-profile 的正确用法

这个配置最常见的正确用法是在 YAML 多文档结构中。比如一个文件包含多段用 --- 分隔的配置:

# 第一段 — 所有 profile 共享的配置
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/db

---
# 第二段 — 仅 dev 环境
spring:
  config:
    activate:
      on-profile: dev
server:
  port: 8080
logging:
  level: DEBUG

---
# 第三段 — 仅 prod 环境
spring:
  config:
    activate:
      on-profile: prod
server:
  port: 80
logging:
  level: WARN

这里 on-profile 的作用是:这段配置只在指定 profile 激活时才生效

错误模式

# ❌ 错误:把过滤器当激活器用
spring:
  config:
    import:
      - classpath:xxx.yml
    activate:
      on-profile: dev   # 这会阻止 import,除非 dev 已被激活
# ❌ 错误:在 import 级别加过滤器
spring:
  config:
    activate:
      on-profile: dev
    import:
      - classpath:xxx.yml  # 这个 import 只在 dev 下执行

如果确实不想在所有环境都导入某个配置,正确做法是:

# ✅ 正确:让被导入的文件自己管理 profile
spring:
  config:
    import:
      - classpath:xxx.yml  # 无条件导入

# xxx.yml 内部
---
spring:
  config:
    activate:
      on-profile: dev
# dev 环境配置...

---
spring:
  config:
    activate:
      on-profile: prod
# prod 环境配置...

经验教训

  1. 名字很相似,作用天差地别。 active 是激活器,activate.on-profile 是过滤器。按字面意思理解不够,要搞清楚语义。

  2. 出了问题先看 profile。 "配置值为 null" 这类问题,大概率是配置文件根本没被加载,而 profile 是最常见的根因。

  3. 保持简单。 主配置文件中尽量用 spring.profiles.active 激活 profile,把 spring.config.activate.on-profile 留给 YAML 多文档的内部分段。不要把 import 操作本身也 profile 化,除非有非常明确的场景需求。

  4. 用好启动日志。 Spring Boot 启动时会打印:

    The following N profiles is/are active: "xxx"
    

    看到 "default" 时就要警觉——这通常意味着 profile 没有被正确激活。

总结

配置 类比 何时使用
spring.profiles.active=dev 打开"dev 模式"的开关 主配置中激活环境
spring.config.activate.on-profile: dev "仅限 dev 模式"的标签 YAML 文档段的条件限定

spring.config.activate.on-profile 是一把软刀子——代码看起来是对的,配置看起来也在,运行时却静悄悄地不加载。现在知道了两者的区别,以后遇到这类问题就能一眼看穿了。


欢迎在评论区分享你遇到的 Spring Boot profile 相关的问题。

posted @ 2026-06-05 10:54  司野良  阅读(10)  评论(0)    收藏  举报