@ConfigurationProperties源码分析及某些你可能不知道的特性

1. 可能被忽视的特性

1.1 使用Duration作为时间配置 ★★★★★

ConfigurationClass

@ConfigurationProperties(prefix = "business")
@Configuration
public class BusinessConfig {
   

    private Duration timeout;
	
	// 省略getter和setter
}

application.yaml

business:
  timeout: 30s	

Test

void test() {
   
	assert businessConfig.timeout.toMillis() == 30 * 1000;
	assert durationConfig.timeout.getSeconds() == 30;
}

支持的时间单位

  • ns (纳秒)
  • us (微秒)
  • ms (毫秒)
  • s (秒)
  • m (分)
  • h (时)
  • d (天)

1.2 使用DataSize作为大小配置 ★★★

ConfigurationClass

@ConfigurationProperties(prefix = "business")
@Configuration
public class BusinessConfig {
   

	public DataSize maxFileSize;
	
	// 省略getter和setter
}

application.yaml

business:
  maxFileSize: 2MB

Test

void test() {
   
   assert businessConfig.maxFileSize.toBytes() == 2 * 1024 * 1024;
   assert businessConfig.maxFileSize.toKilobytes() == 2 * 1024;
   assert businessConfig.maxFileSize.toMegabytes() == 2;
}

支持的时间单位(不支持小写)

  • B
  • KB
  • MB
  • GB
  • TB

1.3 基于构造函数注入 ★★★

  • 如果没有标注@ConstructorBinding注解
    • 没有无参构造函数:启动报错
    • 有无参构造函数 : Spring依旧通过setter进行赋值,不会调用有参构造函数
  • 如果标注了@ConstructorBinding注解
    • 通过标注了@ConstructorBinding注解的构造函数进行注入
    private String name;

    private Integer age;

    private Boolean married;

    private List<String> hobby;
	
	public PersonConfig {
   }

    @ConstructorBinding
    public PersonConfig(String name, Integer age, Boolean married, List<String> hobby) {
   
        this.name = name;
        this.age = age;
        this.married = married;
        this.hobby = hobby;
    }

1.4 属性校验 ★★★

ConfigurationClass

@ConfigurationProperties(prefix = "business")
@Configuration
@Validated
public class BusinessConfig {
   

    @NotBlank
    @Length(min = 3)
    private String strProp;

    @Range(min = 0, max = 100)
    private Integer numProp;

    @Size(min = 3)
    private List<Object> listProp;

    @Size(max = 5)
    private Map<String, String> mapProp;
	
	// 省略getter和setter
}

如果任一属性不满足,Spring容器将启动失败,并给予校验失败的提示信息

***************************
APPLICATION FAILED TO START
***************************

Description:

Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'business' to com.zzzj.config.BusinessConfig failed:

    Property: business.strProp
    Value: null
    Reason: 不能为空


Action:

Update your application's configuration

1.5 ignoreInvalidFields★★

如果注解类中字段类型和属性类型不匹配,是否忽略这种情况
默认为不忽略,出现了上述情况将会导致Spring容器启动失败

public @interface ConfigurationProperties {
   
	
	boolean ignoreInvalidFields() default false;
	// ...
}
@Component
@ConfigurationProperties(prefix = "business")
public class BusinessConfig {
   

    public Integer numProp;
	// 省略getter和setter
}

application.yaml

business:
  numProp: stringValue
***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to bind properties under 'business.num-prop' to java.lang.Integer:

    Property: business.num-prop
    Value: zzzj1233
    Origin: "business.numProp" from property source "Inlined Test Properties"
    Reason: failed to convert java.lang.String to java.lang.Integer

Action:

Update your application's configuration

设置ignoreInvalidFields == true后

@Component
@ConfigurationProperties(prefix = "business", ignoreInvalidFields = true)
public class BusinessConfig {
   

    public Integer numProp;

	// 省略getter和setter
}

Test

void test() {
   
   // Spring容器不会启动失败,只是值为null
   assert businessConfig.numProp == null;

1.6 ignoreUnknownFields★

如果属性在配置类中不存在,是否忽略这种情况
默认为忽略,出现了上述情况将会被无视

public @interface ConfigurationProperties {
   
	
	boolean ignoreUnknownFields() default true;
	// ...
}

设置 ignoreUnknownFields == false

ConfigurationClass

@ConfigurationProperties(prefix = "business", ignoreUnknownFields = false)
public class BusinessConfig {
   

	public Integer numProp;
	
	// 省略getter和setter
}

application.yaml

business:
  nonExistentProp: any
***************************
APPLICATION FAILED TO START
***************************

Description:

Binding to target [Bindable@757194dc type = com.zzzj.config.BusinessConfig, value = 'provided', annotations = array<Annotation>[@org.springframework.boot.context.properties.ConfigurationProperties(ignoreInvalidFields=false, ignoreUnknownFields=false, prefix=business, value=business)]] failed:

    Property: business.nonexistentprop
    Value: any
    Origin: "business.nonExistentProp" from property source "Inlined Test Properties"
    Reason: The elements [business.nonexistentprop] were left unbound.

Action:

Update your application's configuration

2. 前置知识

2.1 Binder

  • 用于给Bindable对象的属性进行赋值,在SpringBoot的源码中常常可以见到
  • 其实处理@ConfigurationProperties注解的逻辑并不多,真正赋值的逻辑全都在Binder对象中
  • 可以认为,@ConfigurationProperties的作用就是给标注了注解的对象转换成一个Bindable对象,用Environment#getPropertySources()创建一个Binder对象给Bindable对象赋值

example

public class PersonConfig {
   

    private String name;

    private Integer age;

    private Boolean married;

    private List<String> hobby;
    
    // 省略getter setter toString
}

public void test() throws Exception {
   
    Map<String, Object> map = new HashMap<>(8);
    map.put("person.name", "zzzj");
    map.put("person.age", 99);
    map.put("person.hobby", Arrays.asList("game", "music", "code"));

	// 使用Map构建出一个ConfigurationPropertySource 
    ConfigurationPropertySource propertySource = new MapConfigurationPropertySource(map);

    PersonConfig personConfig = new PersonConfig();
	
    Bindable<PersonConfig> bindable = Bindable.ofInstance(personConfig)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值