属性绑定原理
注意:使用版本为spring-boot-2.2.2.RELEASE
在进行自定义配置的时候,我们通常使用@ConfigurationProperties注解来进行配置文件和配置类的映射,为什么可以映射呢?
主要靠的是@EnableConfigurationProperties注解来进行自动的将外部配置绑定到@ConfigurationProperties
标注的类的属性中
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableConfigurationPropertiesRegistrar.class)
public @interface EnableConfigurationProperties
看到该注解上引入了一个EnableConfigurationPropertiesRegistrar类,这个应该就是关键了
class EnableConfigurationPropertiesRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
registerInfrastructureBeans(registry);
ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
// 将配置的XxxProperties注册到spring容器中
getTypes(metadata).forEach(beanRegistrar::register);
}
// @EnableConfigurationProperties注解中配置的value值,比如@EnableConfigurationProperties(ServerProperties.class),那么得到的值是ServerProperties.class
private Set<Class<?>> getTypes(AnnotationMetadata metadata) {
return metadata.getAnnotations().stream(EnableConfigurationProperties.class)
.flatMap((annotation) -> Arrays.stream(annotation.getClassArray(MergedAnnotation.VALUE)))
.filter((type) -> void.class != type).collect(Collectors.toSet());
}
@SuppressWarnings("deprecation")
static void registerInfrastructureBeans(BeanDefinitionRegistry registry) {
// 将ConfigurationPropertiesBindingPostProcessor注册到spring容器中,ConfigurationPropertiesBindingPostProcessor用于属性绑定
ConfigurationPropertiesBindingPostProcessor.register(registry);
ConfigurationPropertiesBeanDefinitionValidator.register(registry);
ConfigurationBeanFactoryMetadata.register(registry);
}
}
在代码中我们看到了其向spring容器中注册了ConfigurationPropertiesBindingPostProcessor后置处理器,看该类的名字像是进行属性绑定的,来看一下该类的代码逻辑是如何进行属性绑定的
// 只展示了关键方法,其他方法没有展示
public class ConfigurationPropertiesBindingPostProcessor
implements BeanPostProcessor, PriorityOrdered, ApplicationContextAware, InitializingBean {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 进行绑定
bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));
return bean;
}
private void bind(ConfigurationPropertiesBean bean) {
if (bean == null || hasBoundValueObject(bean.getName())) {
return;
}
Assert.state(bean.getBindMethod() == BindMethod.JAVA_BEAN, "Cannot bind @ConfigurationProperties for bean '"
+ bean.getName() + "'. Ensure that @ConstructorBinding has not been applied to regular bean");
try {
this.binder.bind(bean);
}
catch (Exception ex) {
throw new ConfigurationPropertiesBindException(bean, ex);
}
}
}
// ConfigurationPropertiesBinder类
BindResult<?> bind(ConfigurationPropertiesBean propertiesBean) {
// 返回一个绑定了XxxProperties类的Bindable对象target,这个target对象即被外部属性值注入的目标对象
Bindable<?> target = propertiesBean.asBindTarget();
// 得到@ConfigurationProperties注解
ConfigurationProperties annotation = propertiesBean.getAnnotation();
// 得到BindHandler对象(默认是IgnoreTopLevelConverterNotFoundBindHandler对象),
// 用于对ConfigurationProperties注解的ignoreUnknownFields等属性的处理
BindHandler bindHandler = getBindHandler(target, annotation);
// 得到一个Binder对象,并利用其bind方法执行外部属性绑定逻辑
return getBinder().bind(annotation.prefix(), target, bindHandler);
}
// Binder类
private <T> T bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler, Context context,
boolean allowRecursiveBinding, boolean create) {
// 清空Binder的configurationProperty属性值
context.clearConfigurationProperty();
try {
// 调用BindHandler的onStart方法,执行一系列的责任链对象的该方法
Bindable<T> replacementTarget = handler.onStart(name, target, context);
if (replacementTarget == null) {
return handleBindResult(name, target, handler, context, null, create);
}
target = replacementTarget;
// 调用bindObject方法对Bindable对象target的属性进行绑定外部配置的值,并返回赋值给bound对象
Object bound = bindObject(name, target, handler, context, allowRecursiveBinding);
// 封装handleBindResult对象并返回,注意在handleBindResult的构造函数中会调用BindHandler的onSucess,onFinish方法
return handleBindResult(name, target, handler, context, bound, create);
}
catch (Exception ex) {
return handleBindError(name, target, handler, context, ex);
}
}
绑定对象的真正操作在bindObject方法中
private <T> Object bindObject(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler,
Context context, boolean allowRecursiveBinding) {
// 从propertySource中的配置属性,获取ConfigurationProperty对象property即application.properties配置文件中若有相关的配置的话,那么property将不会为null
ConfigurationProperty property = findProperty(name, context);
// 若property为null,则不会执行后续的属性绑定相关逻辑
if (property == null && containsNoDescendantOf(context.getSources(), name) && context.depth != 0) {
return null;
}
// 根据target类型获取不同的Binder,可以是null(普通的类型一般是Null),MapBinder,CollectionBinder或ArrayBinder
AggregateBinder<?> aggregateBinder = getAggregateBinder(target, context);
// 若aggregateBinder不为null,则调用bindAggregate并返回绑定后的对象
if (aggregateBinder != null) {
return bindAggregate(name, target, handler, context, aggregateBinder);
}
// 若property不为null
if (property != null) {
try {
// 绑定属性到对象中,比如配置文件中设置了server.port=8888,那么将会最终调用bindProperty方法进行属性设置
return bindProperty(target, context, property);
}
catch (ConverterNotFoundException ex) {
// We might still be able to bind it using the recursive binders
Object instance = bindDataObject(name, target, handler, context, allowRecursiveBinding);
if (instance != null) {
return instance;
}
throw ex;
}
}
// 只有@ConfigurationProperties注解的类进行外部属性绑定才会走这里
return bindDataObject(name, target, handler, context, allowRecursiveBinding);
}
private Object bindDataObject(ConfigurationPropertyName name, Bindable<?> target, BindHandler handler,
Context context, boolean allowRecursiveBinding) {
if (isUnbindableBean(name, target, context)) {
return null;
}
Class<?> type = target.getType().resolve(Object.class);
if (!allowRecursiveBinding && context.isBindingDataObject(type)) {
return null;
}
// 新建一个DataObjectPropertyBinder的实现类对象,注意这个对象实现了bindProperty方法
DataObjectPropertyBinder propertyBinder = (propertyName, propertyTarget) -> bind(name.append(propertyName),
propertyTarget, handler, context, false, false);
return context.withDataObject(type, () -> {
for (DataObjectBinder dataObjectBinder : this.dataObjectBinders) {
// 真正实现将外部配置属性绑定到@ConfigurationProperties注解的XxxProperties类的属性中的逻辑
Object instance = dataObjectBinder.bind(name, target, context, propertyBinder);
if (instance != null) {
return instance;
}
}
return null;
});
}
© 著作权归作者所有,转载或内容合作请联系作者
喜欢的朋友记得点赞、收藏、关注哦!!!