乐趣区

Spring Boot中的属性绑定

Spring Boot 中的属性绑定
之前翻译了一篇不怎么样的文章,主要是翻译的水平有限,自己翻译的云里雾里,发现平时只会有 @ConfigurationProperties 注解,对 SpringBoot 强大的属性绑定知之甚少,所以以那篇文章为线索,重新学习了一遍。
@ConfigurationProperties
在使用的时候,我们往往只关心两件事,属性怎么绑定,即属性文件中的值和配置类中字段的映射关系;其次是类实例化的时机。故而衍生开来 ConfigurationProperties 有三种用法。
@Component + @ConfigurationProperties
这种用法最简单,直接在 POJO 类上加上注解即可,Spring 容器初始化时就会生成配置类实例了。适合 POJO 类是自定义的。
@Component
@ConfigurationProperties(prefix = “kaka.cream.mail-a”,ignoreUnknownFields = false)
public class MailPropertiesA {
private String name;
private String sex;
private Integer age;
@Bean + @ConfigurationProperties
在配置类中进行装配, 这两个注解均出现在 Configuration 中,对 POJO 无侵入,使用灵活,且集中(均在配置类中处理)
@Bean
@ConfigurationProperties(prefix = “kaka.cream.mail-b”,ignoreUnknownFields = false)
public MailPropertiesB mailPropertiesB(){
MailPropertiesB b = new MailPropertiesB();
return b;
}
@EnableConfigurationProperties + @ConfigurationProperties
Pojo 类上注解 @ConfigurationProperties,在启动类上注解 @EnableConfigurationProperties
@Data
@ConfigurationProperties(prefix = “kaka.cream.mail-c”,ignoreUnknownFields = false)
public class MailPropertiesC {
private String name;
private String sex;
private Integer age;
}
@EnableConfigurationProperties(MailPropertiesC.class)
public class GomvcApplicationTests {
可以在启动类上一目了然的看到启动的配置,且不需要配置类,对第三方使用者比较友好,但是灵活性上没有第二种好。在这三种里面,推荐使用第二种方式。
Environment
存在于 spring boot 首个版本的元老类,它继承自 PropertyResolver,通过它,我们能知道激活的配置文件,以及获取对应参数的值,结合上面第二种在配置类中一起用。较常用的主要有
// 判断是否包含键值
boolean containsProperty(String key);
// 获取属性值,如果获取不到返回 null
String getProperty(String key);
// 获取属性值,如果获取不到返回缺省值
String getProperty(String key, String defaultValue);
// 获取属性对象
<T> T getProperty(String key, Class<T> targetType);
其中最后一个转换是和 Converter 有关的,会依据 sourceType 和 targetType 查找转换器,这个打算下一个章节进行分析,不在这里展开。所以 Environment 适合简单属性值的获取,不知何复杂对象的绑定。
Binder
Binder 是在 Spring Boot2 新引入的 API,从字面就可以看出来,“主打”绑定,可以非常方便的进行类型转化,以及提供回调方法介入绑定的各个阶段进行深度定制,结合上面第二种在配置类中一起用。其主要的类有 Binder, BindResult 和 BindHandler. 比 Environment 好用很多,必备好类。
// 绑定对象
MailPropertiesC propertiesC = Binder.get(environment).bind(“kaka.cream.mail-c”, Bindable.of(MailPropertiesC.class)).get();
// 绑定 Map
Map<String,Object> propMap = Binder.get(environment).bind(“fish.jdbc.datasource”,Bindable.mapOf(String.class, Object.class)).get();
// 绑定列表
List<String> list = Binder.get(environment).bind(“kaka.cream.list”,Bindable.listOf(String.class)).get();
// 转换以及默认值
String datestr = (String) Binder.get(environment).bind(“kaka.cream.date”,Bindable.of(String.class))
.map(String::toUpperCase)
/** .map(new Function(){
@Override
public Object apply(Object o) {
String str = (String)o;
return str.toUpperCase();
}
})**/
.orElse(“bad date string”);

// 绑定过程回调函数,高度定制
LocalDate str = Binder.get(environment).bind(“kaka.cream.date”, Bindable.of(LocalDate.class), new BindHandler() {

@Override
public <T> Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target,
BindContext context) {
log.info(“ 绑定开始 {}”,name);
return target;
}
@Override
public Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result) {
log.info(“ 绑定成功 {}”,target.getValue());
return result;
}

@Override
public Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Exception error) throws Exception {
log.info(“ 绑定失败 {}”,name);
return “ 没有找到匹配的属性 ”;
}

@Override
public void onFinish(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result) throws Exception {
log.info(“ 绑定结束 {}”,name);
}
}).get();

退出移动版