配置管理

Spring Boot 通过统一的 Environment 抽象管理来自不同来源的配置,支持 YAML / Properties 文件、环境变量、命令行参数,并可集成配置中心实现动态刷新。

配置文件格式

YAML vs Properties

两种格式完全等价,推荐使用 YAML(层级清晰,支持列表):

# application.yml
server:
  port: 8080
  servlet:
    context-path: /api
 
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
# application.properties(等价写法)
server.port=8080
server.servlet.context-path=/api
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root

YAML 支持列表写法:

app:
  allowed-origins:
    - http://localhost:3000
    - https://example.com
  # 行内写法也可以
  tags: [java, spring, web]

配置优先级(从高到低)

命令行参数              --server.port=9090
    ↓
系统环境变量            SERVER_PORT=9090
    ↓
JVM 系统属性           -Dserver.port=9090
    ↓
外部配置文件           ./config/application.yml(jar 包同级)
    ↓
classpath 配置文件     src/main/resources/application-{profile}.yml
    ↓
                      src/main/resources/application.yml

同名属性高优先级覆盖低优先级,命令行参数优先级最高,适合生产部署时临时覆盖。

多环境配置隔离(Profile 机制)详见 环境与Profile


读取配置的三种方式

1. @Value(简单属性)

@Service
public class AppService {
 
    @Value("${server.port}")
    private int port;
 
    @Value("${app.name:未命名}")   // 冒号后为默认值
    private String appName;
 
    @Value("${app.allowed-origins}")
    private List<String> allowedOrigins;
 
    // SpEL 表达式
    @Value("#{${app.weights}}")    // 解析 Map
    private Map<String, Integer> weights;
}

@Value 只能注入到 Spring Bean 中,且在构造函数执行之前不可用(构造注入无法用 @Value)。

2. @ConfigurationProperties(类型安全,推荐)

将一组相关属性绑定到 POJO,支持嵌套对象、列表、校验:

@ConfigurationProperties(prefix = "app")
@Validated
public class AppProperties {
 
    @NotBlank
    private String name;
 
    @Min(1) @Max(65535)
    private int port = 8080;
 
    private List<String> allowedOrigins = new ArrayList<>();
 
    private Database database = new Database();
 
    @Data
    public static class Database {
        private String url;
        private int maxPoolSize = 20;
        private Duration timeout = Duration.ofSeconds(30);
    }
    // getters/setters 或 Lombok @Data
}
app:
  name: 我的应用
  port: 8080
  allowed-origins:
    - http://localhost:3000
  database:
    url: jdbc:mysql://localhost:3306/mydb
    max-pool-size: 20
    timeout: 30s     # Duration 自动解析

注册方式(二选一):

// 方式一:在启动类上扫描
@SpringBootApplication
@ConfigurationPropertiesScan
public class Application {}
 
// 方式二:在配置类上显式注册
@Configuration
@EnableConfigurationProperties(AppProperties.class)
public class AppConfig {}

属性绑定规则(Relaxed Binding):

YAML key          → Java 字段
max-pool-size     → maxPoolSize    (kebab-case → camelCase)
MAX_POOL_SIZE     → maxPoolSize    (环境变量 UPPER_SNAKE)
maxPoolSize       → maxPoolSize    (camelCase)

@ConfigurationProperties 的更多细节详见 属性绑定

3. Environment API(动态读取)

@Service
@RequiredArgsConstructor
public class ConfigService {
 
    private final Environment env;
 
    public String getDbUrl() {
        return env.getProperty("spring.datasource.url");
    }
 
    public int getPort(int defaultPort) {
        return env.getProperty("server.port", Integer.class, defaultPort);
    }
 
    public boolean isProd() {
        return env.acceptsProfiles(Profiles.of("prod"));
    }
}

外部化配置

Spring Boot 支持从 jar 包外部读取配置,不重新打包即可修改:

app.jar
config/
  application.yml          ← 覆盖 jar 内配置
  application-prod.yml

或指定任意路径:

java -jar app.jar --spring.config.location=file:/opt/app/config/

多路径用逗号分隔(后者优先级更高):

java -jar app.jar \
  --spring.config.location=classpath:/,file:/opt/app/config/

加密敏感配置

方式一:环境变量(推荐)

不在配置文件中写明文密码,改用占位符从环境变量读取:

spring:
  datasource:
    password: ${DB_PASSWORD}    # 从环境变量读取
  data:
    redis:
      password: ${REDIS_PASSWORD:}  # 可选,默认为空
export DB_PASSWORD=secret
java -jar app.jar

Docker / K8s 中通过 Secret 注入,详见 Docker部署K8s部署

方式二:Jasypt 加密(配置文件内加密)

implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.5'
# 生成密文
java -cp jasypt-3.0.5.jar \
  org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI \
  input="my-secret-password" password="master-key" algorithm="PBEWithMD5AndDES"
# 输出:ENC(xxxxx)
spring:
  datasource:
    password: ENC(xxxxxabcdef)   # jasypt 自动解密
 
jasypt:
  encryptor:
    password: ${JASYPT_MASTER_KEY}   # 主密钥从环境变量注入

配置中心(动态刷新)

Nacos Config

implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config'
spring:
  config:
    import: nacos:application.yml   # Spring Boot 3.x 写法
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        namespace: dev
        group: DEFAULT_GROUP
        file-extension: yaml
        refresh-enabled: true       # 开启动态刷新
@RestController
@RefreshScope          // 标注后,配置变更时 Bean 自动重建
public class ConfigController {
 
    @Value("${feature.enabled:false}")
    private boolean featureEnabled;
 
    @GetMapping("/feature")
    public boolean isFeatureEnabled() {
        return featureEnabled;
    }
}

Spring Cloud Config Server

# 客户端 bootstrap.yml
spring:
  cloud:
    config:
      uri: http://config-server:8888
      label: main
      profile: prod

配置校验

@ConfigurationProperties 类上启用 JSR-303 校验,应用启动时即报错:

@ConfigurationProperties(prefix = "mail")
@Validated
public class MailProperties {
 
    @NotBlank(message = "邮件服务器地址不能为空")
    private String host;
 
    @Min(value = 1, message = "端口号最小为 1")
    @Max(value = 65535, message = "端口号最大为 65535")
    private int port = 25;
 
    @Email(message = "发件人地址格式不正确")
    private String from;
 
    @NotNull
    private Duration timeout = Duration.ofSeconds(10);
}

启动时若配置缺失或格式错误,立即抛出 BindValidationException,快速失败比运行时报错更安全。

参数校验详见 参数校验


配置文档化(IDE 提示支持)

添加元数据处理器,@ConfigurationProperties 类的属性在 IDE 中自动补全和校验:

annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'

手动补充描述(META-INF/additional-spring-configuration-metadata.json):

{
  "properties": [
    {
      "name": "app.name",
      "type": "java.lang.String",
      "description": "应用名称,用于日志和监控标识"
    }
  ]
}

常见问题

问题原因解决方案
@Value 注入 nullBean 未被 Spring 管理(如 new 创建)确保通过 Spring 注入
Profile 配置不生效spring.profiles.active 位置错误放在 application.yml 主文档块
YAML 列表绑定失败环境变量覆盖时格式错误VALUE[0]=x,VALUE[1]=y 或 JSON 格式
Duration 无法解析格式不对使用 10s5m1h 格式
加密配置解密失败主密钥未注入或算法不匹配检查 jasypt.encryptor.password 环境变量

相关链接