Springboot配置属性绑定

Springboot配置属性绑定

配置属性绑定是 Spring Boot 核心特性之一,本质是将配置文件(properties/yaml)中的键值对,映射到 Java 对象 / 变量中,让代码能以面向对象的方式读取配置。

Spring Boot 提供了两种主流绑定方式 @Value 进行单个属性绑定和 @ConfigurationProperties 进行批量绑定。

@ConfigurationProperties

导入配置文件处理器,在配置文件进行数据绑定时就会有提示

xml 复制代码
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring‐boot‐configuration‐processor</artifactId>
     <optional>true</optional>
</dependency>

编写实体类,Person 和 Dog 的 JavaBean

java 复制代码
package com.qcby.springboot.domain;

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

import java.util.Date;
import java.util.List;
import java.util.Map;

@Component
@ConfigurationProperties(prefix = "person")
public class Person {

    private String lastName;

    private Integer age;

    private boolean boss;

    private Date birth;

    private Map<String,String> maps;

    private List<String> list;

    private Dog dog;

    public Person() {
    }

    public Person(String lastName, Integer age, boolean boss, Date birth, Map<String, String> maps, List<String> list, Dog dog) {
        this.lastName = lastName;
        this.age = age;
        this.boss = boss;
        this.birth = birth;
        this.maps = maps;
        this.list = list;
        this.dog = dog;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public boolean isBoss() {
        return boss;
    }

    public void setBoss(boolean boss) {
        this.boss = boss;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Map<String, String> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, String> maps) {
        this.maps = maps;
    }

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person{" +
                "lastName='" + lastName + '\'' +
                ", age=" + age +
                ", boss=" + boss +
                ", birth=" + birth +
                ", maps=" + maps +
                ", list=" + list +
                ", dog=" + dog +
                '}';
    }
}

@ConfigurationProperties 注解用于告知 Spring Boot 将当前类的所有字段与配置文件中相关前缀对应的配置项进行批量绑定;

prefix = "person" 用于明确绑定配置文件中以 person 为前缀的所有子属性,与当前类字段进行一一映射;

关键前提是只有当当前组件是 Spring 容器中的 Bean(通过 @Component 注解注册),才能使用容器提供的@ConfigurationProperties属性绑定功能。

java 复制代码
package com.qcby.springboot.domain;

public class Dog {

    private String name;

    private Integer age;

    public Dog() {
    }

    public Dog(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

application.yml 是 Spring Boot 全局固定名称的配置文件(与 application.properties 功能一致),以数据为核心,语法简洁、层级清晰,比 JSON/XML 更适合作为配置文件。

关键语法规则

缩进控制层级:必须用空格(不能用 Tab),缩进量不固定,同一层级左对齐即可;

大小写敏感:属性名、值的大小写严格区分;

键值分隔:属性名和值之间用 : 分隔,且 : 后必须加空格;

YAML 核心值类型写法

  • 字面量(数字、字符串、布尔)
    字面量是最基础的配置值,直接对应 Java 中的基本类型
    数字 / 布尔:直接写值,无需引号;
    字符串:默认无引号,特殊字符(如 \n)会被当作普通字符;
    双引号(""):不转义特殊字符,按原含义生效;
    单引号(''):转义特殊字符,特殊字符仅作为普通字符串;
  • 对象 / Map(键值对集合)
    对应 Java 中的 Map 或自定义实体类;
    嵌套式通过缩进表示层级,键值之间用 : 分隔(key: value);
    行内式用 {key1: value1, key2: value2, ...} 包裹,逗号分隔;
  • 数组 / List / Set
    元素支持字面量、对象等任意类型;
    缩进式元素前加 - (横杠 + 空格)开头表示列表项,缩进一致;
    行内式用 [值1, 值2, ...] 包裹,逗号分隔;
  • 占位符使用(动态赋值)
    引用已配置的属性:${属性名}
    生成随机值:${random.value}${random.int}${random.int(10)}${random.int[1024,65536]}
    默认值:${属性名:默认值}(属性不存在时用默认值)。

将配置文件中 person 前缀下的所有属性,自动映射到 Person 类的对应字段中,包括基本类型、日期、集合(List/Map)、嵌套对象等,最终通过容器 Bean 在项目中直接使用配置值。

需要注意的是测试单元的三级包与代码的三级包名称需要保持一致

使用 Spring Boot 提供的整合式测试能力需要导入 spring-boot-starter-test 依赖,它的核心设计是 预先整合 Spring Boot 应用测试最常用的框架和工具库,避免手动引入多个测试依赖的繁琐和版本冲突。

xml 复制代码
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
java 复制代码
package com.qcby.springboot;

import com.qcby.springboot.domain.Person;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootTest {

    @Autowired
    private Person person;

    @Test
    public void contextLoads(){
        System.out.println(person);
    }

}

运行 contextLoads() 测试方法时,JUnit 会先读取 @RunWith(SpringRunner.class),使用 Spring 提供的 SpringRunner 运行器(其中 SpringRunner 是 SpringJUnit4ClassRunner 的简化别名),SpringRunner 识别到 @SpringBootTest 注解,触发 SpringBoot 的自动配置,启动 Spring Boot 应用上下文(容器),容器启动过程中会进行扫描组件和属性绑定,扫描项目中的 @Configuration 配置类,找到 Person 类上的 @Component 将其注册为容器 Bean,通过 @ConfigurationProperties(prefix = "person") 读取配置文件中 person 前缀的属性,注入 Person Bean 的字段。容器启动完成后,@Autowired Person person 从容器中找到并注入测试类的 Person Bean,执行 contextLoads() 方法,打印 person 对象,调用 toString() 输出结果,测试结束后,Spring 容器自动销毁,释放资源。

若测试单元的三级包与代码的三级包名称不一致,会出现 Spring Boot 测试启动时找不到核心配置类报错

Spring 测试默认只扫描测试类所在的包(com.qcby.qcbyjy)及其子包,但主配置类在 com.qcby.springboot,不在扫描范围内,所以找不到。

验证YAML 字符串类型写法

双引号("")不转义特殊字符,按原含义生效,单引号('')转义特殊字符,特殊字符仅作为普通字符串


java.util.Date 传统日期类型默认支持斜杠分隔(yyyy/MM/dd)不默认支持横杠分隔(yyyy-MM-dd)格式

验证占位符的使用

@Value 属性注入

@Value 是一个核心注解,用于给 Spring 管理的 Bean 属性注入值

第一种常见注入场景:直接注入常量值

如果属性值是固定的常量,可以直接用 @Value("常量") 注入属性值(字符串需加引号,数字 / 布尔无需,不支持复杂类型的注入),无需配置文件。

java 复制代码
package com.qcby.springboot.domain;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

@Component
public class Person1 {

    @Value("zhangsan@123.com")
    private String Email;

    @Value("zhangsan")
    private String lastName;

    @Value("#{11*2}")
    private Integer age;

    @Value("true")
    private Boolean boss;

    @Value("2025/11/12")
    private Date birth;

    private Map<String,Object> maps;
    private List<Object> list;
    private Dog dog;

    public String getEmail() {
        return Email;
    }

    public void setEmail(String email) {
        Email = email;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Boolean getBoss() {
        return boss;
    }

    public void setBoss(Boolean boss) {
        this.boss = boss;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    public List<Object> getLists() {
        return list;
    }

    public void setLists(List<Object> lists) {
        this.list = lists;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person1{" +
                "Email='" + Email + '\'' +
                ", lastName='" + lastName + '\'' +
                ", age=" + age +
                ", boss=" + boss +
                ", birth=" + birth +
                ", maps=" + maps +
                ", lists=" + list +
                ", dog=" + dog +
                '}';
    }
}

第二种注入配置文件(application.properties/yaml)中的值

java 复制代码
package com.qcby.springboot.domain;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

@Component
public class Person2 {

    @Value("${person.Email}")
    private String Email;

    @Value("${person.lastName}")
    private String lastName;

    @Value("${person.age}")
    private Integer age;

    @Value("${person.boss}")
    private Boolean boss;

    @Value("${person.birth}")
    private Date birth;

    private Map<String,Object> maps;

    private List<Object> list;

    @Autowired
    private Dog1 dog1;

    public String getEmail() {
        return Email;
    }

    public void setEmail(String email) {
        Email = email;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Boolean getBoss() {
        return boss;
    }

    public void setBoss(Boolean boss) {
        this.boss = boss;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    public List<Object> getList() {
        return list;
    }

    public void setList(List<Object> list) {
        this.list = list;
    }

    public Dog1 getDog1() {
        return dog1;
    }

    public void setDog1(Dog1 dog1) {
        this.dog1 = dog1;
    }

    @Override
    public String toString() {
        return "Person2{" +
                "Email='" + Email + '\'' +
                ", lastName='" + lastName + '\'' +
                ", age=" + age +
                ", boss=" + boss +
                ", birth=" + birth +
                ", maps=" + maps +
                ", list=" + list +
                ", dog1=" + dog1 +
                '}';
    }
}
java 复制代码
package com.qcby.springboot.domain;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Dog1 {

    @Value("${person.dog.name}")
    private String name;

    @Value("${person.dog.age}")
    private Integer age;

    public Dog1() {
    }

    public Dog1(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog1{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}


关键特性详解

@Value 获取值与 @ConfigurationProperties 获取值的区别如图:

下面验证在数据校验和松散绑定两个注解的区别

数据校验

进行数据校验首先需要导入依赖,但需要注意的是

Spring Boot 2.3.0 之前,spring-boot-starter-web 会默认传递依赖包含 Hibernate Validator(数据校验核心)的 spring-boot-starter-validation,因此直接使用 @Validated 等校验注解就能正常执行参数校验逻辑;而 2.3.0 及之后,官方为了按需加载依赖、轻量化项目,将 spring-boot-starter-validation 从 spring-boot-starter-web 的默认传递依赖中移除,需手动引入该依赖后,参数校验功能才能正常生效,否则仅能在代码中标记校验注解,运行时校验逻辑不会实际执行。

xml 复制代码
<!-- 2.3.0 之后的版本需手动引入校验 starter -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

@Value 注解不支持数据校验

@ConfigurationProperties 支持数据校验

下面进行具体演示

java 复制代码
package com.qcby.springboot.domain;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person3 {

    @javax.validation.constraints.Email
    @Value("${person.Email}")
    private String Email;

    @NotNull
    @Value("${person.lastName}")
    private String lastName;

    private Integer age;

    private Boolean boss;

    private Date birth;

    private Map<String,Object> maps;

    private List<Object> list;

    private Dog dog;

    public Person3() {
    }

    public Person3(@javax.validation.constraints.Email String email, Integer age, Boolean boss, Date birth, Map<String, Object> maps, List<Object> list, Dog dog) {
        Email = email;
        this.age = age;
        this.boss = boss;
        this.birth = birth;
        this.maps = maps;
        this.list = list;
        this.dog = dog;
    }

    public String getEmail() {
        return Email;
    }

    public void setEmail(String email) {
        Email = email;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Boolean getBoss() {
        return boss;
    }

    public void setBoss(Boolean boss) {
        this.boss = boss;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    public List<Object> getList() {
        return list;
    }

    public void setList(List<Object> list) {
        this.list = list;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person3{" +
                "Email='" + Email + '\'' +
                ", lastName='" + lastName + '\'' +
                ", age=" + age +
                ", boss=" + boss +
                ", birth=" + birth +
                ", maps=" + maps +
                ", list=" + list +
                ", dog=" + dog +
                '}';
    }
}
java 复制代码
package com.qcby.springboot.domain;

public class Dog {

    private String name;

    private Integer age;

    public Dog() {
    }

    public Dog(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Email 被 @Email 注解修饰,配置文件输入的属性 Email 邮箱不合法时会报错

lastName 被 @NotNull 注解修饰,配置文件输入的属性 lastName 为空时会报错

松散绑定

为验证 @ConfigurationProperties 与 @Value 对于松散绑定的区别,下面先添加实体类与配置文件

java 复制代码
package com.qcby.springboot.domain;

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

import java.util.Date;
import java.util.List;
import java.util.Map;

@Component
@ConfigurationProperties(prefix = "person")
//@Validated
public class Person4 {

    private String Email;

    //@Value("${person.last_name}")
    private String last_name;

    private Integer age;

    private Boolean boss;

    private Date birth;

    private Map<String,Object> maps;

    private List<Object> list;

    private Dog dog;

    public Person4() {
    }

    public Person4(String email, Integer age, Boolean boss, Date birth, Map<String, Object> maps, List<Object> list, Dog dog) {
        Email = email;
        this.age = age;
        this.boss = boss;
        this.birth = birth;
        this.maps = maps;
        this.list = list;
        this.dog = dog;
    }

    public String getEmail() {
        return Email;
    }

    public void setEmail(String email) {
        Email = email;
    }

    public String getLast_name() {
        return last_name;
    }

    public void setLast_name(String last_name) {
        this.last_name = last_name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Boolean getBoss() {
        return boss;
    }

    public void setBoss(Boolean boss) {
        this.boss = boss;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    public List<Object> getList() {
        return list;
    }

    public void setList(List<Object> list) {
        this.list = list;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person4{" +
                "Email='" + Email + '\'' +
                ", last_name='" + last_name + '\'' +
                ", age=" + age +
                ", boss=" + boss +
                ", birth=" + birth +
                ", maps=" + maps +
                ", list=" + list +
                ", dog=" + dog +
                '}';
    }
}

@ConfigurationProperties 支持配置名与 Java 属性名的格式自动转换,支持松散绑定

@Value 不支持配置名与 Java 属性名的格式自动转换,必须严格匹配配置名,要求大小写、分隔符完全一致

相关推荐
Acc1oFl4g2 小时前
详解Java反射
java·开发语言·python
海上彼尚2 小时前
Go之路 - 6.go的指针
开发语言·后端·golang
Trouvaille ~2 小时前
【Java篇】存在即不变:深刻解读String类不变的艺术
java·开发语言·javase·stringbuilder·stringbuffer·string类·字符串常量池
lemon_sjdk2 小时前
java学习——枚举类
java·开发语言·学习
2022.11.7始学前端2 小时前
n8n第九节 使用LangChain与Gemini构建带对话记忆的AI助手
java·人工智能·n8n
LYFlied2 小时前
在AI时代,前端开发者如何构建全栈开发视野与核心竞争力
前端·人工智能·后端·ai·全栈
用户47949283569153 小时前
我只是给Typescript提个 typo PR,为什么还要签协议?
前端·后端·开源
Surpass余sheng军3 小时前
AI 时代下的网关技术选型
人工智能·经验分享·分布式·后端·学习·架构
JosieBook3 小时前
【Spring Boot】Spring Boot调用 WebService 接口的两种方式:动态调用 vs 静态调用 亲测有效
java·spring boot·后端