文章目录
1. 为什么要使用Binder
举个例子,假设Spring的Environment内有以下属性
public Environment mockEnvironment() {
return new MockEnvironment()
.withProperty("user.name", "zzzj")
.withProperty("user.age", "25")
.withProperty("user.gender", "male")
.withProperty("user.fullname", "${user.name}1233")
.withProperty("hobby[0]", "eat")
.withProperty("hobby[1]", "drink")
.withProperty("hobby[2]", "play");
}
以Json的形式表示Environment
的属性如下
{
"user": {
"name": "zzzj",
"age": "25",
"gender": "male",
"fullname": "${user.name}1233"
},
"hobby": [
"eat",
"drink",
"play"
]
}
那么有这样一个需求
- 如何以
user
为前缀获取一个对象 - 如何以
hobby
为前缀获取一个数组
2. 通过environment
的api获取 — 失败
@Test
public void getPropertyByEnvironment() {
Environment environment = mockEnvironment();
// 无法直接获取user
assertNull(environment.getProperty("user"));
// 可以通过具体的属性名获取到user.name
assertEquals("zzzj", environment.getProperty("user.name"));
// 无法直接获取hobby
assertNull(environment.getProperty("hobby"));
// 可以通过具体的属性名获取到hobby的第一项
assertEquals("eat", environment.getProperty("hobby[0]"));
}
根据上述代码可知
environment.getProperty
只能获取到具体的属性, 而无法通过前缀获取属性集合
3. 通过Binder
获取 — 满足需求
@Test
public void getPropertyByBinder() throws Exception {
Binder binder = Binder.get(mockEnvironment());
// 获取user属性, 作为一个 Map<String, Object>
BindResult<Map<String, Object>> result = binder.bind("user", Bindable.mapOf(String.class, Object.class));
assertThat(result.get())
.hasSize(4)
.containsEntry("name", "zzzj")
.containsEntry("age", "25")
.containsEntry("gender", "male")
.containsEntry("fullname", "zzzj1233");
// 获取hobby属性, 作为一个 String[]
BindResult<String[]> hobby = binder.bind("hobby", Bindable.of(String[].class));
assertThat(hobby.get())
.hasSize(3)
.containsExactly("eat", "drink", "play");
}
4. @ConfigurationProperties与Binder
在SpringBoot中有一个众所周知的注解@ConfigurationProperties
就是通过Binder
来实现的
源码路径
org.springframework.boot.context.properties.ConfigurationPropertiesBinder#bind