首页 / Spring Boot 入门教程 / 配置属性绑定

Spring Boot 入门教程

配置属性绑定

本教程共 48 篇 · 第 11 篇 · 更新于 2026-08-13 · 约 4 分钟阅读

@ConfigurationProperties@Value类型安全属性绑定配置校验宽松绑定

本节目标:用 @ConfigurationProperties 把配置绑成类型安全对象,掌握注册、嵌套、校验和与 @Value 的取舍。

为什么需要类型安全绑定

上一章里,我们用 @Value 读单个属性。属性一多,问题就来了:

  • 十几个 @Value 散落在类里,乱。
  • 值全是字符串,类型转换靠自己。
  • 拼错键名,运行到一半才报错。

@ConfigurationProperties 换个思路:把一组前缀相同的属性,整体绑进一个 Java 对象。

类型转换、键名校验,框架全包了。这就是「类型安全配置」。

第一个绑定示例

先写配置,放在 src/main/resources/application.yml

app:
  name: hello-app
  version: 1.0.0
  author: 码上学

再写一个普通 Java 类接收它:

import org.springframework.boot.context.properties.ConfigurationProperties;

@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {

    private String name;
    private String version;
    private String author;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}

三个要点:

  • @ConfigurationProperties(prefix = "app") 声明前缀。
  • @Component 让它成为 Bean。
  • JavaBean 规范要求提供 getter/setter,绑定靠 setter 完成。
Note

prefix 必须用小写 kebab-case,比如 my-app。写 myAppMyApp 会出问题。

其他类直接注入这个对象即可:

import org.springframework.stereotype.Service;

@Service
public class AppService {

    private final AppProperties props;

    public AppService(AppProperties props) {
        this.props = props;
    }

    public String describe() {
        return props.getName() + " v" + props.getVersion() + " by " + props.getAuthor();
    }
}

三种注册方式

@Component 只是其中一种。官方还提供两种:

方式一:@EnableConfigurationProperties

适合不想给类加 @Component 的场景:

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(AppProperties.class)
public class AppConfig {
}

方式二:@ConfigurationPropertiesScan

在主类上开启扫描,自动发现所有 @ConfigurationProperties 类:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;

@SpringBootApplication
@ConfigurationPropertiesScan
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

三种方式任选其一。小型项目用 @Component 最省事,组件库场景常用后两种。

嵌套对象

配置有层级时,用嵌套类对应:

app:
  name: hello-app
  security:
    username: admin
    password: secret
    roles:
      - USER
      - ADMIN
import java.util.ArrayList;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;

@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {

    private String name;
    private Security security = new Security();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Security getSecurity() {
        return security;
    }

    public void setSecurity(Security security) {
        this.security = security;
    }

    public static class Security {
        private String username;
        private String password;
        private List<String> roles = new ArrayList<>();

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public List<String> getRoles() {
            return roles;
        }

        public void setRoles(List<String> roles) {
            this.roles = roles;
        }
    }
}

嵌套对象预初始化后可以省略 setter,绑定器直接往里填值。

绑定 Map

键不固定的配置,用 Map 接。比如一组按节点名区分的地址:

app:
  nodes:
    node-1:
      ip: 10.0.0.1
      port: 8080
    node-2:
      ip: 10.0.0.2
      port: 8080
import java.util.LinkedHashMap;
import java.util.Map;

import org.springframework.boot.context.properties.ConfigurationProperties;

@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {

    private Map<String, Node> nodes = new LinkedHashMap<>();

    public Map<String, Node> getNodes() {
        return nodes;
    }

    public void setNodes(Map<String, Node> nodes) {
        this.nodes = nodes;
    }

    public static class Node {
        private String ip;
        private int port;

        public String getIp() {
            return ip;
        }

        public void setIp(String ip) {
            this.ip = ip;
        }

        public int getPort() {
            return port;
        }

        public void setPort(int port) {
            this.port = port;
        }
    }
}

Map 的 key 就是配置里的键名,运行时动态取:

appProperties.getNodes().get("node-1").getIp();

绑定第三方组件

类不是自己写的,没法加注解。

这时把 @ConfigurationProperties 放到 @Bean 方法上:

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ThirdPartyConfig {

    @Bean
    @ConfigurationProperties(prefix = "another")
    public AnotherComponent anotherComponent() {
        return new AnotherComponent();
    }
}

another 前缀下的属性会自动绑到 AnotherComponent 实例上。

前提是第三方类遵循 JavaBean 规范,有对应的 setter。

构造器绑定与 record

想要不可变对象?用构造器绑定。类上只有一个有参构造器时,Spring Boot 自动启用:

import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;

@ConfigurationProperties(prefix = "app")
public class AppProperties {

    private final String name;
    private final Security security;

    public AppProperties(String name, Security security) {
        this.name = name;
        this.security = security;
    }

    public String getName() {
        return name;
    }

    public Security getSecurity() {
        return security;
    }

    public static class Security {
        private final String username;
        private final String password;
        private final List<String> roles;

        public Security(String username, String password,
                        @DefaultValue("USER") List<String> roles) {
            this.username = username;
            this.password = password;
            this.roles = roles;
        }

        public String getUsername() {
            return username;
        }

        public String getPassword() {
            return password;
        }

        public List<String> getRoles() {
            return roles;
        }
    }
}

@DefaultValue 给缺失的属性提供默认值。字段全变 final,对象不可变,更安全。

Note

构造器绑定的类不能靠 @Component 注册(官方明确不支持),必须用 @EnableConfigurationProperties(AppProperties.class) 或在启动类加 @ConfigurationPropertiesScan 启用扫描。

Java 16+ 还可以直接用 record:

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "app")
public record AppProperties(String name, String version, String author) {
}

record 同样不能靠 @Component 注册,用 @EnableConfigurationProperties(AppProperties.class)@ConfigurationPropertiesScan 启用。

Note

构造器绑定要求编译时带 -parameters 参数。用 spring-boot-starter-parent 或官方 Gradle 插件时自动开启,不用管。

宽松绑定

Spring Boot 的绑定规则很宽松。字段 firstName 可以接受这些写法:

写法示例
kebab-case(推荐)app.first-name
驼峰app.firstName
下划线app.first_name
环境变量APP_FIRSTNAME

官方建议配置文件里统一用小写 kebab-case。

好处是:换环境、换配置来源时,键名不用改。这一特性在第 12 章的环境变量部分还会用到。

属性校验

配合 Jakarta Validation,启动时就能校验配置。先加依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

再给配置类加上校验注解:

import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

@Component
@ConfigurationProperties(prefix = "app")
@Validated
public class AppProperties {

    @NotEmpty
    private String name;

    @NotNull
    @Size(min = 1, max = 10)
    private String version;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }
}

校验失败时应用直接启动失败,并给出明确错误信息。

嵌套对象的校验要加 @Valid 才会级联生效:

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;

@Valid
private Security security = new Security();

public static class Security {
    @NotEmpty
    private String username;
}
Tip

配置写错了早失败,比运行时炸掉好得多。关键配置务必加校验。

类型转换

字符串属性会自动转成目标类型。

int、long、boolean、枚举、日期都没问题。官方还内置了 Duration 和 DataSize 的转换:

app:
  timeout: 30s
  max-size: 10MB
import java.time.Duration;

import org.springframework.util.unit.DataSize;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {

    private Duration timeout;
    private DataSize maxSize;

    public Duration getTimeout() {
        return timeout;
    }

    public void setTimeout(Duration timeout) {
        this.timeout = timeout;
    }

    public DataSize getMaxSize() {
        return maxSize;
    }

    public void setMaxSize(DataSize maxSize) {
        this.maxSize = maxSize;
    }
}

30s 自动解析为 30 秒,10MB 解析为 10 兆字节。

这类可读写法比裸数字友好得多,配置里优先用。

IDE 自动补全

@ConfigurationProperties 类还能给 IDE 提供元数据,写配置时有自动补全和文档提示。

加一个可选依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

编译时它会扫描配置类,生成 spring-configuration-metadata.json

重新编译后,在 application.yml 里输入 app. 就有候选提示。

Tip

想给属性写注释说明?在字段上加 Javadoc 注释,IDE 提示会显示出来。

@ConfigurationProperties 与 @Value 怎么选

官方对比表浓缩成三行:

能力@ConfigurationProperties@Value
宽松绑定完整支持有限支持
元数据与 IDE 提示支持不支持
SpEL 表达式不支持支持

选型建议:

  • 一组相关属性 → 用 @ConfigurationProperties。
  • 单个零散属性 → 用 @Value。
  • 需要 SpEL 计算(如 ${random.int} 之外的表达式)→ 只能用 @Value。

记住一句话:自己定义的配置组,优先 @ConfigurationProperties。

小结

  • @ConfigurationProperties 把同前缀属性绑成对象,类型安全。
  • 注册方式有 @Component、@EnableConfigurationProperties、@ConfigurationPropertiesScan 三种。
  • 支持嵌套、列表、Map、构造器绑定和 record。
  • 加 @Validated 后可用 Jakarta Validation 校验配置。
  • 一组属性用 @ConfigurationProperties,单个属性用 @Value。
  • 第三方类用 @Bean 方法绑定。
  • Map、Duration、DataSize 都有内置支持。
  • 加 configuration-processor 依赖,IDE 补全配置键。