1. 简介

Spring Boot 提供了强大的外部化配置功能,能轻松处理属性文件中的配置项。本文将深入探讨 @ConfigurationProperties 注解的核心用法和高级特性。

2. 环境准备

首先在 pom.xml 中添加标准依赖:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.1.5</version>
    <relativePath/>
</parent>

为启用属性校验功能,添加验证依赖:

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

⚠️ 更多 Hibernate Validator 细节可参考官方文档

3. 基础属性绑定

最佳实践是将配置属性隔离到独立 POJO 中

@Configuration
@ConfigurationProperties(prefix = "mail")
public class ConfigProperties {
    
    private String hostName;
    private int port;
    private String from;

    // 标准 getter/setter
}

关键点说明:

  • @Configuration 使 Spring 创建 Bean
  • prefix = "mail" 指定公共前缀
  • 必须提供标准 setter 方法

✅ 如果不使用 @Configuration,需在主类添加 @EnableConfigurationProperties(ConfigProperties.class)

Spring 支持灵活的属性名绑定规则:

mail.hostName
mail.hostname
mail.host_name
mail.host-name
mail.HOST_NAME

对应配置文件示例:

# 基础属性
mail.hostName=smtp.example.com
mail.port=9000
mail.from=admin@example.com

3.1. Spring Boot 2.2 新特性

从 2.2 版本开始,Spring 通过类路径扫描自动注册 @ConfigurationProperties

@ConfigurationProperties(prefix = "mail") 
@ConfigurationPropertiesScan 
public class ConfigProperties { 

    private String hostName; 
    private int port; 
    private String from; 

    // 标准 getter/setter 
}

✅ 无需再添加 @Component@EnableConfigurationProperties

自定义扫描路径示例:

@SpringBootApplication
@ConfigurationPropertiesScan("com.example.config")
public class DemoApplication { 
    public static void main(String[] args) {   
        SpringApplication.run(DemoApplication.class, args); 
    } 
}

4. 嵌套属性处理

支持 ListMap 和自定义类的嵌套结构:

public class Credentials {
    private String authMethod;
    private String username;
    private String password;

    // 标准 getter/setter
}

更新主配置类:

public class ConfigProperties {
    private String hostname;
    private int port;
    private String from;
    private List<String> defaultRecipients;
    private Map<String, String> additionalHeaders;
    private Credentials credentials;
 
    // 标准 getter/setter
}

对应配置文件:

# 基础属性
mail.hostName=smtp.example.com
mail.port=9000
mail.from=admin@example.com

# List 属性
mail.defaultRecipients[0]=dev@example.com
mail.defaultRecipients[1]=ops@example.com

# Map 属性
mail.additionalHeaders.redelivery=true
mail.additionalHeaders.secure=true

# 对象属性
mail.credentials.username=john
mail.credentials.password=secret
mail.credentials.authMethod=SHA1

5. 在 @Bean 方法上使用

适用于绑定第三方组件的属性

public class Item {
    private String name;
    private int size;

    // 标准 getter/setter
}

配置类示例:

@Configuration
public class ConfigProperties {

    @Bean
    @ConfigurationProperties(prefix = "item")
    public Item item() {
        return new Item();
    }
}

所有 item 前缀的属性将自动绑定到该 Bean

6. 属性校验

通过 JSR-380 规范实现强大校验能力

@NotBlank
private String hostName;

@Length(max = 4, min = 1)
private String authMethod;

@Min(1025)
@Max(65536)
private int port;

@Pattern(regexp = "^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,6}$")
private String from;

❌ 校验失败将导致应用启动失败并抛出 IllegalStateException

⚠️ 必须提供标准 getter/setter 才能使校验生效

7. 属性类型转换

7.1. Duration 类型

private Duration timeInDefaultUnit;
private Duration timeInNano;

@DurationUnit(ChronoUnit.DAYS)
private Duration timeInDays;

配置示例:

conversion.timeInDefaultUnit=10
conversion.timeInNano=9ns
conversion.timeInDays=2

✅ 支持单位:ns, us, ms, s, m, h, d,默认毫秒

7.2. DataSize 类型

private DataSize sizeInDefaultUnit;
private DataSize sizeInGB;

@DataSizeUnit(DataUnit.TERABYTES)
private DataSize sizeInTB;

配置示例:

conversion.sizeInDefaultUnit=300
conversion.sizeInGB=2GB
conversion.sizeInTB=4

✅ 支持单位:B, KB, MB, GB, TB,默认字节

7.3. 自定义转换器

实现 Converter 接口处理特殊类型:

public class Employee {
    private String name;
    private double salary;
}

转换器实现:

@Component
@ConfigurationPropertiesBinding
public class EmployeeConverter implements Converter<String, Employee> {

    @Override
    public Employee convert(String from) {
        String[] data = from.split(",");
        return new Employee(data[0], Double.parseDouble(data[1]));
    }
}

配置示例:

conversion.employee=john,2000

8. 不可变属性绑定

Spring Boot 2.2+ 支持构造器绑定实现不可变配置

@ConfigurationProperties(prefix = "mail.credentials")
public class ImmutableCredentials {

    private final String authMethod;
    private final String username;
    private final String password;

    @ConstructorBinding
    public ImmutableCredentials(String authMethod, String username, String password) {
        this.authMethod = authMethod;
        this.username = username;
        this.password = password;
    }

    // 省略其他构造器和 getter
}

⚠️ 所有字段必须是 final,且无 setter 方法

✅ 需通过 @EnableConfigurationProperties@ConfigurationPropertiesScan 显式启用

9. Java 16 Record 支持

Record 类型天然适合配置属性场景

@ConstructorBinding
@ConfigurationProperties(prefix = "mail.credentials")
public record ImmutableCredentials(
    String authMethod, 
    String username, 
    String password
) {}

✅ Spring Boot 2.6+ 对单构造器 Record 可省略 @ConstructorBinding

10. 总结

@ConfigurationProperties 提供了:

  • ✅ 灵活的属性绑定机制
  • ✅ 强大的类型转换能力
  • ✅ 完整的 JSR-380 校验支持
  • ✅ 不可变配置实现方案
  • ✅ Java Record 原生支持

完整示例代码请参考 GitHub 仓库


原始标题:Guide to @ConfigurationProperties in Spring Boot | Baeldung