如何实现递归赋值配置类成员变量?
JavaBeanBinder
接上一篇文章代码
绑定Bean属性会调用 propertyBinder.bindProperty
private <T> boolean bind(BeanSupplier<T> beanSupplier,
BeanPropertyBinder propertyBinder, BeanProperty property) {
String propertyName = property.getName();
ResolvableType type = property.getType();
Supplier<Object> value = property.getValue(beanSupplier);
Annotation[] annotations = property.getAnnotations();
//这里就是上面提到的回调函数,会递归对象属性赋值
Object bound = propertyBinder.bindProperty(propertyName,
Bindable.of(type).withSuppliedValue(value).withAnnotations(annotations));
if (bound == null) {
return false;
}
//判断有setter方法,调用赋值,用的是java 反射技术
if (property.isSettable()) {
property.setValue(beanSupplier, bound);
}
else if (value == null || !bound.equals(value.get())) {
throw new IllegalStateException(
"No setter found for property: " + property.getName());
}
return true;
}
BeanPropertyBinder
BeanPropertyBinder 是一个接口,这个接口只有一个函数
interface BeanPropertyBinder {
/**
* Bind the given property.
* @param propertyName the property name (in lowercase dashed form, e.g.
* {@code first-name})
* @param target the target bindable
* @return the bound value or {@code null}
*/
Object bindProperty(String propertyName, Bindable<?> target);
}
Binder
上面的 propertyBinder是在这里创建并传入的 BeanPropertyBinder propertyBinder = (propertyName, propertyTarget) -> bind(name.append(propertyName), propertyTarget, handler, context, false);
因此这里用lambda实现了这个接口
private Object bindBean(ConfigurationPropertyName name, Bindable<?> target,
BindHandler handler, Context context, boolean allowRecursiveBinding) {
if (containsNoDescendantOf(context.streamSources(), name)
|| isUnbindableBean(name, target, context)) {
return null;
}
BeanPropertyBinder propertyBinder = (propertyName, propertyTarget) -> bind(
name.append(propertyName), propertyTarget, handler, context, false);
Class<?> type = target.getType().resolve(Object.class);
if (!allowRecursiveBinding && context.hasBoundBean(type)) {
return null;
}
return context.withBean(type, () -> {
Stream<?> boundBeans = BEAN_BINDERS.stream()
.map((b) -> b.bind(name, target, context, propertyBinder));
return boundBeans.filter(Objects::nonNull).findFirst().orElse(null);
});
}
protected final <T> T bind(ConfigurationPropertyName name, Bindable<T> target,
BindHandler handler, Context context, boolean allowRecursiveBinding) {
context.clearConfigurationProperty();
try {
if (!handler.onStart(name, target, context)) {
return null;
}
Object bound = bindObject(name, target, handler, context,
allowRecursiveBinding);
return handleBindResult(name, target, handler, context, bound);
}
catch (Exception ex) {
return handleBindError(name, target, handler, context, ex);
}
}
private <T> Object bindObject(ConfigurationPropertyName name, Bindable<T> target,
BindHandler handler, Context context, boolean allowRecursiveBinding) {
ConfigurationProperty property = findProperty(name, context);
if (property == null && containsNoDescendantOf(context.streamSources(), name)) {
return null;
}
AggregateBinder<?> aggregateBinder = getAggregateBinder(target, context);
if (aggregateBinder != null) {
return bindAggregate(name, target, handler, context, aggregateBinder);
}
if (property != null) {
try {
return bindProperty(target, context, property);
}
catch (ConverterNotFoundException ex) {
// We might still be able to bind it as a bean
Object bean = bindBean(name, target, handler, context,
allowRecursiveBinding);
if (bean != null) {
return bean;
}
throw ex;
}
}
return bindBean(name, target, handler, context, allowRecursiveBinding);
}
这里又递归调用回来了最开始的bindBean方法,就这样实现了递归
private Object bindBean(ConfigurationPropertyName name, Bindable<?> target,
BindHandler handler, Context context, boolean allowRecursiveBinding) {
if (containsNoDescendantOf(context.streamSources(), name)
|| isUnbindableBean(name, target, context)) {
return null;
}
BeanPropertyBinder propertyBinder = (propertyName, propertyTarget) -> bind(
name.append(propertyName), propertyTarget, handler, context, false);
Class<?> type = target.getType().resolve(Object.class);
if (!allowRecursiveBinding && context.hasBoundBean(type)) {
return null;
}
return context.withBean(type, () -> {
Stream<?> boundBeans = BEAN_BINDERS.stream()
.map((b) -> b.bind(name, target, context, propertyBinder));
return boundBeans.filter(Objects::nonNull).findFirst().orElse(null);
});
}
总结
如何实现递归赋值配置类成员变量?
在JavaBeanBinder给对象赋值前会递归调用Binder中创建并实现的BeanPropertyBinder 接口方法,从而实现递归调用功能会在此调用到JavaBeanBinder对象,直到遍历所有属性赋值。