点击关注公众号,更多资讯及时推送↓
引言
SpringBoot中极大的简化了项目中对于属性配置的加载方式,可以简单的通过 @Value, @ConfigurationProperties 来实现属性配置与Java POJO对象、Bean的成员变量的绑定,那如果出现一个某些场景,需要我们手动的、通过编程式的方式,将属性配置与给定的pojo对象进行绑定,我们又应该怎么实现呢?
项目配置
首先搭建一个标准的SpringBoot项目工程,相关版本以及依赖如下
本项目借助SpringBoot 2.2.1.RELEASE
+ maven 3.5.3
+ IDEA
进行开发
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
代码演示
首先先给大家介绍下编程式的属性绑定,除了我们最熟悉的直接从 Environment 中获取配置之外,还可以使用 Binder来实现属性绑定。
// 获取binder实例
public static Binder get(Environment environment) {
return get(environment, (BindHandler)null);
}
// 属性绑定
// Bind the specified target Class using this binder's property sources.
<T> BindResult<T> bind(String name, Class<T> target)
<T> BindResult<T> bind(String name, Bindable<T> target, BindHandler handler)
// Bind the specified target Class using this binder's property sources or create a new instance using the type of the Bindable if the result of the binding is null.
<T> T bindOrCreate(String name, Class<T> target)
<T> T bindOrCreate(String name, Bindable<T> target, BindHandler handler)
两种常见的使用方式:
-
bind方法: 将属性绑定到对应的类上, 不会返回null
-
bindOrCreate: 将属性绑定到对应的类上, 返回结果可能为null
直接将配置绑定在我们自定义的配置类上,也就是我们常用的方式 @ConfigurationProperties 注解来实现的方式:
demo:
mail:
host: smtp.163.com
from: xhhuiblog@163.com
username: test
password: testpwd
port: 465
接下来定义一个对应的属性配置类Mail
@Data
public class Mail {
private String host;
private String port;
private String user;
private String password;
private String from;
}
使用方式:
@Component
public class BindHelper implements EnvironmentAware {
private Environment environment;
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
public void bindInfo() {
// 直接将前缀对应的配置,加载到指定的对象中
Binder binder = Binder.get(environment);
// 直接绑定到配置类
Mail mail = binder.bindOrCreate("demo.mail", Mail.class);
System.out.println("mail = " + mail);
}
}
在上面的基础使用方式之上,我们再加两个使用方式
-
配置不存在时,返回什么?
-
使用bind对于不存在时,如何表现
-
public void bindInfo() {
// 直接将前缀对应的配置,加载到指定的对象中
Binder binder = Binder.get(environment);
// 直接绑定到配置类
Mail mail = binder.bindOrCreate("demo.mail", Mail.class);
System.out.println("mail = " + mail);
mail = binder.bindOrCreate("demo.mail2", Mail.class);
System.out.println("mail = " + mail);
try {
mail = binder.bind("demo.mail2", Mail.class).get();
System.out.println("mail = " + mail);
} catch (Exception e) {
// 因为配置不存在,会报错
System.out.println(e.getMessage());
}
}
执行之后,输出如下
从上面的输出可以看出,对于
-
bindOrCreat 而言,若整个配置不存在,返回一个空对象,内部属性为null;bind 若相关的配置不存在,会抛异常 (这个不存在指的是配置前缀demo.mail2的都没有)
-
配置内的某个属性不存在,如 demo.mail.user 这个配置不存在时(配置中的是username),此时bind/bindOrCrate 返回的对象中,相关的属性是null (注意这种场景 bind 方法调用不会抛移异常,有兴趣的小伙伴可以实际验证一下)
配置绑定到List对象
在实际的应用场景中,配置为数组的可能性也很高,比如我有一个代理库,对应的相关配置如下
demo:
proxy:
- ip: 127.0.0.1
port: 1080
- ip: localhost
port: 1800
此时我们的实际使用姿势可以如下
-
首先定义Proxy类
-
@Data
public class Proxy {
private String ip;
private Integer port;
}
对应的手动绑定方式
// 将配置绑定到list
List<Proxy> proxyList = binder.bind("demo.proxy", Bindable.listOf(Proxy.class)).get();
// 或者直接使用 binder.bindOrCreate("demo.proxy", Bindable.listOf(Proxy.class))
System.out.println("list config: " + proxyList);
配置绑定到Map对象
demo:
dynamic:
master:
user: main
password: m1
slave:
user: slave
password: s1
@Data
public class DsConfig {
private String user;
private String password;
}
Map<String, DsConfig> dsMap = binder.bind("demo.dynamic", Bindable.mapOf(String.class, DsConfig.class)).get();
System.out.println("Map Config: " + dsMap);
Map Config: {master=BindHelper.DsConfig(user=main, password=m1), slave=BindHelper.DsConfig(user=slave, password=s1)}
配置转换处理
demo:
enc:
pwd: 5LiA54Gw54GwYmxvZw==
// 对配置进行解析
String decPwd = binder.bind("demo.enc.pwd", Bindable.of(String.class))
.map(s -> new String(Base64Utils.decodeFromString(s))).get();
System.out.println("解码之后的数据是: " + decPwd);
解码之后的数据是: Java技术前沿
绑定方法回调
// 注册绑定过程回调
String dec = binder.bindOrCreate("demo.enc.pwd", Bindable.of(String.class), new BindHandler() {
@Override
public <T> Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target, BindContext context) {
System.out.println("开始绑定: " + name);
return BindHandler.super.onStart(name, target, context);
}
@Override
public Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result) {
System.out.println("绑定成功!" + name + " val:" + target.getValue() + " res: " + result);
return new String(Base64Utils.decodeFromString((String) result));
}
@Override
public Object onCreate(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result) {
System.out.println("创建: " + name + " val:" + target.getValue() + " res: " + result);
return BindHandler.super.onCreate(name, target, context, result);
}
@Override
public Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Exception error) throws Exception {
System.out.println("绑定失败! " + name + " " + error.getMessage());
return BindHandler.super.onFailure(name, target, context, error);
}
@Override
public void onFinish(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result) throws Exception {
System.out.println("绑定结束: " + name + " val:" + target.getValue() + " res: " + result);
BindHandler.super.onFinish(name, target, context, result);
}
});
System.out.println("绑定回调:" + dec);
开始绑定: demo.enc.pwd
绑定成功!demo.enc.pwd val:null res: 5LiA54Gw54GwYmxvZw==
绑定结束: demo.enc.pwd val:null res: Java技术前沿绑定回调: Java技术前沿
小结
原文始发于微信公众号(Java技术前沿):SpringBoot 实战:Spring Boot的配置绑定类Bindable居然如此强大
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/299582.html