Spring Boot2.0的属性绑定

原文
从Spring boot第一个版本以来,我们可以使用@ConfigurationProperties注解将属性绑定到对象。也可以指定属性的各种不同格式。比如,person.first-name,person.firstName和PERSON_FIRSTNAME都可以使用。这个功能叫做“relaxed binding”。

不幸的是,在spring boot 1.x,“relaxed binding”显得太随意了。从而使得很难来定义准确的绑定规则和指定使用的格式。在1.x的实现中,也很难对其进行修正。比如,在spring boot 1.x中,不能将属性绑定到java.util.Set对象。

所以,在spring boot 2.0中,开始重构属性绑定的功能。我们添加了一些新的抽象类和一些全新的绑定API。在本篇文章中,我们会介绍其中一些新的类和接口,并介绍添加他们的原因,以及如何在自己的代码中如何使用他们。

Property Sources

如果你已经使用spring有一段时间,你应该对Environment比较熟悉了。这个接口继承了PropertyResolver,让你从一些PropertySource的实现解析属性。

Spring Framework提供了一些常用的PropertySource,如系统属性,命令行属性,属性文件等。Spring Boot自动配置这些实现(比如加载application.properties)。

Configuration Property Sources

比起直接使用已存在的PropertySource实现类,Spring Boot2.0引入了新的ConfigurationPropertySource接口。我们引入这个新的接口来定义“relaxed binding”规则。

该接口的主要API显得非常简单

ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name);

另外有个IterableConfigurationPropertySource变量实现了Iterable<ConfigurationPropertyNaame>,让你可以发现source包含的所有属性名称。

你可以向下面这样将Environment传给ConfigurationPropertySources:

sources = ConfigurationPropertySources.get(environment);" title="" data-original-title="复制">

Iterable<ConfigurationPropertySource> sources = ConfigurationPropertySources.get(environment);

我们同时提供了MapConfigurationPropertySource来帮你应付上面的场景。

Configuration Property Names

如果规则明确,实现"relaxed binding"会简单很多。一直使用一致的格式,而不需要去关系在source中的各种无规则的格式。

ConfigurationPropertyNames类来强制进行这些属性命名规则,例如“use lowercase kebab-case names”,在代码中使用person.first-name,在source中使用person.firstName或者PERSON_FIRSTNAME.

Origin Support

如期望的那样,ConfigurationPropertySource返回ConfigurationProperty对象,里面包含了属性的取值,另外有个可选的Origin对象。

spring boot 2.0引入了新的接口Origin,能够指出属性取值的准确位置。其中TextResourceOrigin是较为常用的实现,会提供所加载的Resource,以及对应的行。

对于.properties和.yml文件,我们写了定制的souce加载器,使得追踪成为可能。一些spring boot的功能进行了重写来追踪信息。比如,属性绑定的验证异常现在会显示:

Description:

Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'person' to scratch.PersonProperties failed:

Property: person.name
Value: Joe
Origin: class path resource [application.properties]:1:13
Reason: length must be between 4 and 2147483647

Action:

Update your application's configuration" title="" data-original-title="复制">



APPLICATION FAILED TO START

Description: Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'person' to scratch.PersonProperties failed: Property: person.name

Value: Joe

Origin: class path resource [application.properties]:1:13

Reason: length must be between 4 and 2147483647 Action: Update your application's configuration

Binder API

org.springframework.boot.context.properties.bind.Binder类允许你使用多个ConfigurationPropertySource。准确的说,Binder使用Bindable并返回一个BindResult.

Bindable

一个Bindable可以是Java bean,或是一个复杂对象(如List<Person>).这里是一些例子

Bindable.ofInstance(existingBean);
Bindable.of(Integer.class);
Bindable.listOf(Person.class);
Bindable.of(resovableType);

Binable用来携带注解的信息,但不需要太过关注这个。

BindResult

binder会返回BindResult,和java8 stream操作返回的Optional很相似,一个BinderResult表示bind的结果。

如果你尝试获取一个没有绑定的对象,会抛出异常,另外有其他的方法来设置没有绑定时的缺省对象。

//返回LocalDate,如果没有则抛出异常

bound.get()

//返回一个格式化时间,或是“No DOB"

bound.map(dateFormatter::format).orElse("NO DOB");

//返回LocalDate或者抛出自定义异常

bound.orElseThrow(NoDateOfBirthException::new);

" title="" data-original-title="复制">

var bound = binder.bind("person.date-of-birth",Bindable.of(LocalDate.class));

//返回LocalDate,如果没有则抛出异常

bound.get() //返回一个格式化时间,或是“No DOB"

bound.map(dateFormatter::format).orElse("NO DOB"); //返回LocalDate或者抛出自定义异常

bound.orElseThrow(NoDateOfBirthException::new);

Formatting and Conversion

大部分ConfigurationPropertySource实现将值当字符串处理。当Binder需要将值转化为其他类型时,会使用到Spring的ConversionService API。比较常用的是@NumberFormat和@DateFormat这两个注解。

spring boot 2.0也引入了一些新的注解和转换器。例如,你现在可以将4s转换成Duration。具体请参考org.springframework.boot.conver包。

BindHandler

在binding的过程中,你可能会需要实现一些额外的逻辑。BindHandler接口提供了这样的机会。每一个BindHandler有onStart, onSuccess, onFailure和 onFinish方法供重载。

spring boot提供了一些handlers,用来支持已存在的@ConfigurationProperties binding。 比如 ValidationBindHandler可以用于绑定对象的合法性校验上。

@ConfigurationProperties

如文章开头所提到的,@ConfigurationProperties是在spring boot最初就加入的功能。所以大部分人会继续使用该注解是不可避免的。

Future Work

我们计划在spring boot2.1中继续加强Binder的功能,而第一个想要支持的功能是不可变属性绑定。另外相较getters和setters的绑定,使用基于构造器的绑定来代替:

public class Person{
private final String firstName;
private final String lastName;
private final LocalDateTime dateOfBirth;
public Person(String firstName, String lastName, LocalDateTime dateOfBirth){
this.firstName = firstName;
this.lastName = lastName;
this.dateOfBirth = dateOfBirth;
}
//getters
}

Summary

我们希望在spring boot2.0 中你可以找到更好用的属性绑定功能,并考虑升级你目前的方式。

原文地址:https://segmentfault.com/a/1190000018773800?utm_source=tag-newest

Spring Boot 2.0的属性绑定的更多相关文章

  1. Spring Boot 2.0 的配置绑定类Bindable居然如此强大

    1. 前言 在开发Spring Boot应用时会用到根据条件来向Spring IoC容器注入Bean.比如配置文件存在了某个配置属性才注入Bean : 图中红色的部分是说,只有ali.pay.v1.a ...

  2. Spring Boot 2.0系列文章(七):SpringApplication 深入探索

    关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/30/springboot_SpringApplication/ 前言 在 Spring B ...

  3. 详细介绍Spring Boot 2.0的那些新特性与增强

    以Java 8 为基准 Spring Boot 2.0 要求Java 版本必须8以上, Java 6 和 7 不再支持. 内嵌容器包结构调整 为了支持reactive使用场景,内嵌的容器包结构被重构了 ...

  4. Spring Boot 2.0 升级指南

    Spring Boot 2.0 升级指南 前言 Spring Boot已经发布2.0有5个月多,多了很多新特性,一些坑也慢慢被填上,最近有空,就把项目中Spring Boot 版本做了升级,顺便整理下 ...

  5. Spring Boot 2.0 新特性和发展方向

    以Java 8 为基准 Spring Boot 2.0 要求Java 版本必须8以上, Java 6 和 7 不再支持. 内嵌容器包结构调整 为了支持reactive使用场景,内嵌的容器包结构被重构了 ...

  6. Spring Boot 2.0正式发布,新特性解读

    作者|翟永超 Spring Boot 2.0 来啦,有哪些新特性?升级吗? 写在前面 北京时间 3 月 1 日,经过漫长的等待之后,Spring Boot 2.0 正式发布.作为 Spring 生态中 ...

  7. 【2.0新特性】Spring Boot 2.0新特性

    以Java 8 为基准 Spring Boot 2.0 要求Java 版本必须8以上, Java 6 和 7 不再支持. 内嵌容器包结构调整 为了支持reactive使用场景,内嵌的容器包结构被重构了 ...

  8. Spring Boot实践——Spring Boot 2.0 新特性和发展方向

    出自:https://mp.weixin.qq.com/s/EWmuzsgHueHcSB0WH-3AQw 以Java 8 为基准 Spring Boot 2.0 要求Java 版本必须8以上, Jav ...

  9. Spring Boot 2.0 新特性

    这是一篇总结文章,主要收集 Spring Boot 2.0 相对于 Spring Boot 1.x 的新特性,本章节并不提供实践性质的源代码.在 Spring Boot 系列文章中会持续退出实践章节. ...

随机推荐

  1. ios Enum Value To NSString

    #define enumToString(value)  @#value eg. typedef NS_ENUM(NSInteger, Sex) { Male = 0, Famale = 1, }; ...

  2. 2.eclipse 插件安装烦死人(2)

    安装插件的实际结果是:(烦死人),要不是很多插件找不到,要不就是版本不对,要不就是下载了装上没有效果,要不就是在线安装(速度爆慢),好不容易等到结果了,结果是些错…… 最后我的eclipse 3.5. ...

  3. mystr = '{}{}{}'.format(mystr, random.randint(0, 9), adurl)

    mystr = '{}{}{}'.format(mystr, random.randint(0, 9), adurl)

  4. CSP 201612-3 权限查询 【模拟+STL】

    201612-3 试题名称: 权限查询 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 授权 (authorization) 是各类业务系统不可缺少的组成部分,系统用户通过授权 ...

  5. vi/vim命令

    vi / vim是Unix / Linux上最常用的文本编辑器而且功能非常强大.

  6. ‘CONFIG_ENV_SIZE’未声明(不在函数内【转】

    本文转载自: http://bbs.csdn.net/topics/390678466 见论坛讨论.可以临时修复.

  7. POJ 3734 Blocks 矩阵递推

    POJ3734 比较简单的递推题目,只需要记录当前两种颜色均为偶数, 只有一种颜色为偶数 两种颜色都为奇数 三个数量即可,递推方程相信大家可以导出. 最后来个快速幂加速即可. #include< ...

  8. 洛谷P3690 LCT模板

    题目:https://www.luogu.org/problemnew/show/P3690 自己竟然从没有钻研过LCT上的连通性问题! 于是被最后一个点卡了,似乎因为 find 函数只能找出连通性而 ...

  9. Java中try,catch,finally的用法

    Java中try,catch,finally的用法,以前感觉还算熟悉,但看到一篇博文才有更深点的理解,总结网友博客如下. Java异常处理的组合方式: 1.try+catch  运行流程:运行到try ...

  10. Java 泛型 三

    一.泛型初衷 Java集合不会知道我们需要用它来保存什么类型的对象,所以他们把集合设计成能保存任何类型的对象,只要就具有很好的通用性.但这样做也带来两个问题: –集合对元素类型没有任何限制,这样可能引 ...