要想了解 ConfigurationProperties 的原理,咱得先了解一下 BeanPostProcessor 是个啥
简单说,BeanPostProcessor 接口我们也叫后置处理器,作用是在Bean对象实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。是 springboot 的一个核心接口
ok,进入正题
进入 ConfigurationProperties
也可以看看,@Index注解是什么
@AliasFor:别名
ConfigurationPropertiesBindingPostProcessor 实现的接口
实现自己老爸的核心方法之一: postProcessBeforeInitialization(Object bean, String beanName) 方法
——那么 谁在调用这个方法?
- 实现默认 bean 创建的抽象 bean 工厂超类,具有RootBeanDefinition类指定的全部功能。 除了 AbstractBeanFactory 的createBean方法之外,还实现AutowireCapableBeanFactory接口。
- 提供 bean 创建(具有构造函数解析)、属性填充、接线(包括自动接线)和初始化。 处理运行时 bean 引用、解析托管集合、调用初始化方法等。支持自动装配构造函数、按名称的属性和按类型的属性。
就是这玩意 –> applyBeanPostProcessorsBeforeInitialization()
@Override
// 在初始化之前应用 Bean 后处理器
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
// 已实例化的 bean
Object result = existingBean;
// 遍历每一个 BeanPostProcessor ,Bean 的初始化时处理器
// getBeanPostProcessors():返回将应用于使用此工厂创建的 bean 的 BeanPostProcessor 列表
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 对应的 processor 做对应的初始化前的处理(大部分 processor 在这里实际上都没有做任何对 bean 的处理)
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
// 所有的处理器做完处理之后,返回处理后的 bean (当然一顿遍历下来也可能所有的处理器没有做任何处理,直接返回原对象)
return result;
}
——那我们的 ConfigurationPropertiesBindingPostProcessor 是在什么时候登场的呢?他登场的条件是什么?他是如何做处理的?
我们 debug 进入上面分析到的 postProcessBeforeInitialization(Object bean, String beanName) 内的 get() 方法中一探究竟
说明这个方法旨在寻找 bean 或工厂方法,如果 bean 或工厂方法都没有用@ConfigurationProperties注释,则为配置属性 bean 或null
所以, bean 不是@ConfigurationProperties对象,则返回null 。(——null 是什么时候返回的?)
ConfigurationPropertiesBean.get() 源码附下:
public static ConfigurationPropertiesBean get(ApplicationContext applicationContext, Object bean, String beanName) {
Method factoryMethod = findFactoryMethod(applicationContext, beanName);
return create(beanName, bean, bean.getClass(), factoryMethod);
}
ok,那我们先写一个测试对象测试一下
跟踪 PersonPerson 类
@Data
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private Integer age;
}
application.yml
person: name: liu age: 18
看一下我们这个 ConfigurationPropertiesBindingPostProcessor 是如何处理条件的
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// (一)
bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));
return bean;
}
// (二)
private void bind(ConfigurationPropertiesBean bean) {
// (三)
// 在这里判断,如果 bean 为空,或者 此时的 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);
}
}
private boolean hasBoundValueObject(String beanName) {
return this.registry.containsBeanDefinition(beanName) && this.registry
.getBeanDefinition(beanName) instanceof ConfigurationPropertiesValueObjectBeanDefinition;
}
(三)进入 hasBoundValueObject(String beanName)
1.先看 containsBeanDefinition() 方法: BeanDefinition 包含我们的 bean,bean 在实例化的时候就已经做了,使用返回 true
2.再判断 this.registry.getBeanDefinition(beanName) instanceof ConfigurationPropertiesValueObjectBeanDefinition
- ConfigurationPropertiesValueObjectBeanDefinition:BeanDefinition用于注册在创建时绑定的@ConfigurationProperties值对象 bean。
此时我们的 person 对象还未对配置文件中的属性进行绑定,返回 false
所以,bean == null || hasBoundValueObject(bean.getName()) 返回 false,我们找到了我们要 bind 的 bean 对象了!
上面的判断 ,如果 bean 为空,或者有绑定值对象直接返回寂寞,此时已经经过了 get() 返回,如果是 ConfigurationProperties 注解注释的类返回的 bean 才是不为空的 bean,才允许继续执行 this.binder.bind(bean)
——咦?他啥时候返回的空?
我们再回去看一眼 create() 方法
OK,
那我们先直接快速 debug 到我们使用到 @ConfigurationProperties 的地方,紧接着上面 进入该方法
源码附下
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
ConfigurationPropertiesBinder:ConfigurationPropertiesBindingPostProcessor用于处理实际@ConfigurationProperties绑定的内部类。
debug 进入 bind()
注意 :此时的 propertiesBean :里面的 instance 就是一个空壳 Person 实例
悄悄 透个剧:
| 后面我们会在 bindObject() 方法中的 bindDataObject() 方法中详细说明 name 属性和 age 属性是如何悄无声息地潜入 Person 对象的 |
提个醒,bind() 是我们之后的核心方法,着重看这个方法,其他的不是主线
继续看这个 bind() 方法
- Bindable target:[Bindable@31e32ea2 type = com.dongua.Person, value = ‘provided’, annotations = array[@org.springframework.boot.context.properties.ConfigurationProperties(ignoreInvalidFields=false, ignoreUnknownFields=true, prefix=person, value=person)]]
说明一下这几个类
- Bindable:asBindTarget() 返回一个适合用作Binder目标的Bindable实例,可以由Binder绑定的源。
- BindHandler:可用于在元素binding期间处理附加逻辑的回调接口
- BindResult:一个容器对象,用于返回Binder绑定操作的结果。 可能包含成功绑定的对象或空结果。
那么前两个方法没啥好说了,
咱进入 getBindHandler()
privateBindHandler getBindHandler(Bindable target, ConfigurationProperties annotation) { // (一):没有任何的校验器,直接返回空的 List List validators = getValidators(target); // (二) BindHandler handler = getHandler(); // 什么也没做,只一次判空断言 handler = new ConfigurationPropertiesBindHander(handler); // 对一些注解的属性判断,没有以下符合的条件,直接跳过 // 都是字面意思,对应 ConfigurationProperties 的属性 if (annotation.ignoreInvalidFields()) { handler = new IgnoreErrorsBindHandler(handler); } if (!annotation.ignoreUnknownFields()) { UnboundElementsSourceFilter filter = new UnboundElementsSourceFilter(); handler = new NoUnboundElementsBindHandler(handler, filter); } // 没有校验器 if (!validators.isEmpty()) { handler = new ValidationBindHandler(handler, validators.toArray(new Validator[0])); } // 看一下有没有什么附加功能,没有直接跳过 for (ConfigurationPropertiesBindHandlerAdvisor advisor : getBindHandlerAdvisors()) { handler = advisor.apply(handler); } // 直接返回 return handler; } // (二) private IgnoreTopLevelConverterNotFoundBindHandler getHandler() { // (1)实例化当前上下文的 BoundConfigurationProperties 对象 BoundConfigurationProperties bound = BoundConfigurationProperties.get(this.applicationContext); return (bound != null) // 不为空,走第一个方法获取 IgnoreTopLevelConverterNotFoundBindHandler 对象 ? new IgnoreTopLevelConverterNotFoundBindHandler(new BoundPropertiesTrackingBindHandler(bound::add)) : new IgnoreTopLevelConverterNotFoundBindHandler(); } // (一):没有任何的校验器,直接返回空的 List private List getValidators(Bindable> target) { List validators = new ArrayList<>(3); if (this.configurationPropertiesValidator != null) { validators.add(this.configurationPropertiesValidator); } if (this.jsr303Present && target.getAnnotation(Validated.class) != null) { validators.add(getJsr303Validator()); } if (target.getValue() != null && target.getValue().get() instanceof Validator) { validators.add((Validator) target.getValue().get()); } return validators; }
(1)BoundConfigurationProperties bound:空壳
(二) hander
也可以看看:@FunctionalInterface是什么
OK,进入关键方法:getBinder().bind(annotation.prefix(), target, bindHandler)
随之进入 Binder
- Binder:从一个或多个ConfigurationPropertySources绑定对象的容器对象。注意这个容器对象,后面会经常看到它
bind(String name, Bindable target, BindHandler handler) :使用此Bindable器的property sources绑定指定的目标Bindable
publicBindResult bind(String name, Bindable target, BindHandler handler) { return bind(ConfigurationPropertyName.of(name), target, handler); }
——啥玩意?
不急,先跟踪 ConfigurationPropertyName.of(name) 方法看他怎么处理的我们的前缀 prefix
进入 ConfigurationPropertyName
- 由点分隔的元素组成的配置属性名称。 用户创建的名称可能包含字符“ az ”“ 0-9 ”)和“ - ”,它们必须是小写的并且必须以字母数字字符开头。 “ - ”纯粹用于格式化,即“ foo-bar ”和“ foobar ”被认为是等效的。
- “ [ ”和“ ] ”字符可用于表示关联索引(即Map键或Collection索引。索引名称不受限制,并被视为区分大小写。
下面是一些典型的例子:
- spring.main.banner-mode
- server.hosts[0].name
- log[org.springboot].level
追踪到最后处理的函数
经过一系列封装,校验,转换,返回处理 prefix 之后的封装对象ConfigurationPropertyName
static ConfigurationPropertyName of(CharSequence name, boolean returnNullIfInvalid) {
Elements elements = elementsOf(name, returnNullIfInvalid);
return (elements != null) ? new ConfigurationPropertyName(elements) : null;
}
获取的 ConfigurationPropertyName 对象:已经拿到 person前缀
那我们继续 bind()
进入方法内部
// 没啥好看 privateT bind(ConfigurationPropertyName name, Bindable target, BindHandler handler, boolean create) { Assert.notNull(name, "Name must not be null"); Assert.notNull(target, "Target must not be null"); // 我们的 hander 不为空,依然用自己的 handler = (handler != null) ? handler : this.defaultBindHandler; Context context = new Context(); // 继续往下 return bind(name, target, handler, context, false, create); } // 来到了这 private T bind(ConfigurationPropertyName name, Bindable target, BindHandler handler, Context context, boolean allowRecursiveBinding, boolean create) { try { // (一) Bindable replacementTarget = handler.onStart(name, target, context); if (replacementTarget == null) { return handleBindResult(name, target, handler, context, null, create); } target = replacementTarget; // 这就是前边提到的绑定配置文件内属性的方法! // (二)绑定对象(透露:根据我们的例子,我们会经历三次该方法,对象本身以及他的所有属性 person ,name ,age) Object bound = bindObject(name, target, handler, context, allowRecursiveBinding); return handleBindResult(name, target, handler, context, bound, create); } catch (Exception ex) { return handleBindError(name, target, handler, context, ex); } }
(一) handler.onStart(name, target, context)
Bindable replacementTarget:这个类放的是我们 binder 的一些资源
现在我们直接进入 bindObject() 揭开面纱
privateObject bindObject(ConfigurationPropertyName name, Bindable target, BindHandler handler, Context context, boolean allowRecursiveBinding) { // (一) 寻找属性 (伏笔) ConfigurationProperty property = findProperty(name, target, context); if (property == null && context.depth != 0 && containsNoDescendantOf(context.getSources(), name)) { return null; } // 没有绑定这玩意 ,跳过 AggregateBinder> aggregateBinder = getAggregateBinder(target, context); if (aggregateBinder != null) { return bindAggregate(name, target, handler, context, aggregateBinder); } // property 为 null,跳过 if (property != null) { try { 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; } } // 在确认确实没有绑定且符合各种条件之后,开始进行数据绑定 return bindDataObject(name, target, handler, context, allowRecursiveBinding); }
(一)findProperty(name, target, context):不是我们想要的
(这里为后面的属性执行埋下伏笔,这里的限制是在限制什么?)
都是一些判断和确认,我们直接进入 bindDataObject() 函数内部
private Object bindDataObject(ConfigurationPropertyName name, Bindable> target, BindHandler handler,
Context context, boolean allowRecursiveBinding) {
// 判断这个 bean 到底能不能绑定
if (isUnbindableBean(name, target, context)) {
return null;
}
Class> type = target.getType().resolve(Object.class);
if (!allowRecursiveBinding && context.isBindingDataObject(type)) {
return null;
}
DataObjectPropertyBinder propertyBinder = (propertyName, propertyTarget) -> bind(name.append(propertyName),
propertyTarget, handler, context, false, false);
// 暗藏玄机:所有的谜底都将在这里发现
return context.withDataObject(type, () -> {
for (DataObjectBinder dataObjectBinder : this.dataObjectBinders) {
Object instance = dataObjectBinder.bind(name, target, context, propertyBinder);
if (instance != null) {
return instance;
}
}
return null;
});
}
到这里我们其实可以大致猜想一下代码的执行流程,他一定是先去判断你这个 bean 是否符合我的各种条件,比如是否被 configurationproperties所注释,在ioc容器找不找的到 这个bean等等,然后就是拿到这个符合条件的bean,我们再去寻找有没有对应的配置文件能够为这个bean对象初始化一些属性,也就是绑定数据给这个bean,找到并且绑定成功之后就开始这个bean的其他操作,听起来挺简单哇。继续往后…(如果感到些许疲惫了先喝口水,后面要加速了)
那我们先看看这个 isUnbindableBean() 做了那些判断
private boolean isUnbindableBean(ConfigurationPropertyName name, Bindable> target, Context context) {
// 1.在当前上下文中遍历所有的 ConfigurationPropertySource 并找出 符合条件的 source
for (ConfigurationPropertySource source : context.getSources()) {
// 2.条件:这个 person 包不包含在我们的配置文件中
// 3.当前我们寻找了: OriginTrackedMapPropertySource
// 4.详情: {name='Config resource 'class path resource [application.yml]' via location 'optional:classpath:/''}
// 5.也就是说,在 class path resource [application.yml] 发现了我们的 person !
if (source.containsDescendantOf(name) == ConfigurationPropertyState.PRESENT) {
// 6.此时,我们得到状态 PRESENT == ConfigurationPropertyState.PRESENT
// 官方注释: We know there are properties to bind so we can't bypass anything
// 翻译:我们知道有要绑定的属性所以我们不能绕过任何东西
// 7.返回,继续
return false;
}
}
// ..
}
判断完毕,继续执行
private Object bindDataObject(ConfigurationPropertyName name, Bindable> target, BindHandler handler,
Context context, boolean allowRecursiveBinding) {
// false
if (isUnbindableBean(name, target, context)) {
return null;
}
// 解析得到目标类型
Class> type = target.getType().resolve(Object.class);
// 再确定一次是否可以绑定数据,可以绑定,跳过
if (!allowRecursiveBinding && context.isBindingDataObject(type)) {
return null;
}
// 可由DataObjectBinder实现用来绑定数据对象属性的 Binder。
// 函数表达式真..影响阅码体验,后面还有一堆..
// 这里的 bind() 就是执行 bindObject() 方法的 bind() 方法
// 总之知道 DataObjectPropertyBinder 咋来的就行 (噩梦开始的地方)
// 如下图
DataObjectPropertyBinder propertyBinder = (propertyName, propertyTarget) -> bind(name.append(propertyName),
propertyTarget, handler, context, false, false);
return context.withDataObject(type, () -> {
//
for (DataObjectBinder dataObjectBinder : this.dataObjectBinders) {
// 获取绑定之后的实例对象!
Object instance = dataObjectBinder.bind(name, target, context, propertyBinder);
if (instance != null) {
return instance;
}
}
return null;
});
}
DataObjectPropertyBinder propertyBinder
(吃个加速包,请系好安全带)
继续往下执行
// 又是一个函数式引用..
// 接着往下
return context.withDataObject(type, () -> {
for (DataObjectBinder dataObjectBinder : this.dataObjectBinders) {
Object instance = dataObjectBinder.bind(name, target, context, propertyBinder);
if (instance != null) {
return instance;
}
}
return null;
});
withDataObject()
privateT withDataObject(Class> type, Supplier supplier) { // 在执行数据绑定之前放我们的 bean 类型进去 this.dataObjectBindings.push(type); try { // 执行之前会增加一个 Depth return withIncreasedDepth(supplier); } finally { // 执行完删掉之前保存的bean类型 this.dataObjectBindings.pop(); } }
withIncreasedDepth(supplier);
privateT withIncreasedDepth(Supplier supplier) { // 执行之前增加一个 Depth increaseDepth(); try { return supplier.get(); } finally { // 执行结束 减掉一个 Depth decreaseDepth(); } }
比如,increaseDepth() ,this.depth++;
// depth 加一
private void increaseDepth() {
this.depth++;
}
进行执行 supplier.get(); 之前,我们需要回到 withDataObject() 中
return context.withDataObject(type, () -> {
// 开始遍历
// 只有俩,看下图
for (DataObjectBinder dataObjectBinder : this.dataObjectBinders) {
Object instance = dataObjectBinder.bind(name, target, context, propertyBinder);
if (instance != null) {
return instance;
}
}
return null;
});
经过判断
那我们就往下走 dataObjectBinder.bind(name, target, context, propertyBinder)
进入 JavaBeanBinder数一数这是第几个 bind() 方法?
bind()
@Override publicT bind(ConfigurationPropertyName name, Bindable target, Context context, DataObjectPropertyBinder propertyBinder) { // 继续遍历寻找可以胜任的 Properties 进行绑定 boolean hasKnownBindableProperties = target.getValue() != null && hasKnownBindableProperties(name, context); Bean bean = Bean.get(target, hasKnownBindableProperties); if (bean == null) { return null; } BeanSupplier beanSupplier = bean.getSupplier(target); boolean bound = bind(propertyBinder, bean, beanSupplier, context); return (bound ? beanSupplier.get() : null); }
就是这个 OriginTrackedMapPropertySource
详情: {name=‘Config resource ‘class path resource [application.yml]’ via location ‘optional:classpath:/’’}
再接着往下执行 get()
@Override publicT bind(ConfigurationPropertyName name, Bindable target, Context context, DataObjectPropertyBinder propertyBinder) { // (一) boolean hasKnownBindableProperties = target.getValue() != null && hasKnownBindableProperties(name, context); // =============进入============ Bean bean = Bean.get(target, hasKnownBindableProperties); / .. }
staticBean get(Bindable bindable, boolean canCallGetValue) { // com.dongua.Person ResolvableType type = bindable.getType(); // class com.dongua.Person Class> resolvedType = type.resolve(Object.class); // value 存储参数: Person(name=null, age=null) Supplier value = bindable.getValue(); T instance = null; // canCallGetValue 传进来就是 true if (canCallGetValue && value != null) { // (一)继续执行 instance = value.get(); resolvedType = (instance != null) ? instance.getClass() : resolvedType; } if (instance == null && !isInstantiable(resolvedType)) { return null; } Bean> bean = Bean.cached; if (bean == null || !bean.isOfType(type, resolvedType)) { // (二)确认没有 bean ,自己 new bean = new Bean<>(type, resolvedType); cached = bean; } return (Bean ) bean; }
(一)instance = value.get():获取没有初始化属性值的实例对象
// 使用 现有值 创建更新的Bindable实例 // 现有值 existingValue : Person(name=null, age=null) public BindablewithExistingValue(T existingValue) { Assert.isTrue( existingValue == null || this.type.isArray() || this.boxedType.resolve().isInstance(existingValue), () -> "ExistingValue must be an instance of " + this.type); // 在这里调用了 get() 方法,不作处理直接返回 Supplier value = (existingValue != null) ? () -> existingValue : null; return new Bindable<>(this.type, this.boxedType, value, this.annotations, this.bindRestrictions); }
(二)bean = new Bean<>(type, resolvedType);
(再吃个加速包~)
继续执行 new Bean<>()
Bean(ResolvableType type, Class> resolvedType) {
this.type = type;
this.resolvedType = resolvedType;
// 获取配置文件
addProperties(resolvedType);
}
addProperties()
private void addProperties(Class> type) {
while (type != null && !Object.class.equals(type)) {
Method[] declaredMethods = getSorted(type, Class::getDeclaredMethods, Method::getName);
Field[] declaredFields = getSorted(type, Class::getDeclaredFields, Field::getName);
addProperties(declaredMethods, declaredFields);
type = type.getSuperclass();
}
}
person 的 declaredMethods
person 的 declaredFields
下一个 addProperties() 方法
protected void addProperties(Method[] declaredMethods, Field[] declaredFields) {
for (int i = 0; i < declaredMethods.length; i++) {
if (!isCandidate(declaredMethods[i])) {
declaredMethods[i] = null;
}
}
for (Method method : declaredMethods) {
addMethodIfPossible(method, "is", 0, BeanProperty::addGetter);
}
for (Method method : declaredMethods) {
addMethodIfPossible(method, "get", 0, BeanProperty::addGetter);
}
for (Method method : declaredMethods) {
addMethodIfPossible(method, "set", 1, BeanProperty::addSetter);
}
for (Field field : declaredFields) {
addField(field);
}
}
经过一些列反射操作之后,把属性填充到我们当前对象 JavaBeanBinder 中
回到 get()
staticBean get(Bindable bindable, boolean canCallGetValue) { // .. Bean> bean = Bean.cached; if (bean == null || !bean.isOfType(type, resolvedType)) { // bean 相关成员已经拿到手 bean = new Bean<>(type, resolvedType); // 加入缓存 cached = bean; } // 返回 return (Bean ) bean; }
回到 bind()
@Override publicT bind(ConfigurationPropertyName name, Bindable target, Context context, DataObjectPropertyBinder propertyBinder) { boolean hasKnownBindableProperties = target.getValue() != null && hasKnownBindableProperties(name, context); // 但是数据还没塞进去 Bean bean = Bean.get(target, hasKnownBindableProperties); if (bean == null) { return null; } // (一)获取结果的提供商 BeanSupplier beanSupplier = bean.getSupplier(target); // (二) boolean bound = bind(propertyBinder, bean, beanSupplier, context); return (bound ? beanSupplier.get() : null); }
BeanSupplier 实现了 Supplier 接口,前面提到过 Supplier ,最后我们经过处理会返回其封装的结果
——为什么需要这个提供商呢?
此时提供商还未提供任何属性数据,我们继续往下执行
(二)bind(propertyBinder, bean, beanSupplier, context);
privateboolean bind(DataObjectPropertyBinder propertyBinder, Bean bean, BeanSupplier beanSupplier, Context context) { boolean bound = false; // 遍历我们刚刚获取的 Properties 里面的 属性,也就是 name 属性和 age 属性 for (BeanProperty beanProperty : bean.getProperties().values()) { // 这是什么意思? bound |= bind(beanSupplier, propertyBinder, beanProperty); context.clearConfigurationProperty(); } return bound; }
- 解释一下 |=
比如, a|=b 的意思就是把a和b 按位或 然后赋值给a
按位或的意思就是先把a和b都换成二进制,然后用或操作,相当于 a=a|b
不急,先往下看这个 bind() 方法有什么与众不同
// 也不知道这是第几个 bind() 方法了 .. privateboolean bind(BeanSupplier beanSupplier, DataObjectPropertyBinder propertyBinder, BeanProperty property) { // 不重要,往下看 String propertyName = property.getName(); ResolvableType type = property.getType(); // (一)这里再此出现了 Supplier Supplier
property.getValue(beanSupplier);
Supplier
Supplier value:
(二)继续往下,绑定属性
propertyBinder.bindProperty(propertyName,Bindable.of(type).withSuppliedValue(value).withAnnotations(annotations));
// 又回到这个方法
private Object bindDataObject(ConfigurationPropertyName name, Bindable> target, BindHandler handler,
Context context, boolean allowRecursiveBinding) {
// ..
// 此处,propertyBinder 的 bind 方法还未执行完成
DataObjectPropertyBinder propertyBinder = (propertyName, propertyTarget) ->
// 进入这个方法
bind(name.append(propertyName),
propertyTarget, handler, context, false, false);
return context.withDataObject(type, () -> {
for (DataObjectBinder dataObjectBinder : this.dataObjectBinders) {
Object instance = dataObjectBinder.bind(name, target, context, propertyBinder);
if (instance != null) {
return instance;
}
}
return null;
});
}
我们又回到了这里 bindDataObject() 方法,而 DataObjectBinder 就是我们之前说的,实现用来绑定数据对象属性的 Binder
我们先执行 name.append(propertyName) 方法,看一下我们属性名字是如何被处理的
public ConfigurationPropertyName append(String suffix) {
if (!StringUtils.hasLength(suffix)) {
return this;
}
// 看到了熟悉的 Elements ,这不就是我们之前处理 person 前缀的其中一个封装类吗
// probablySingleElementOf 处理这个后缀 person.xxx
Elements additionalElements = probablySingleElementOf(suffix);
return new ConfigurationPropertyName(this.elements.append(additionalElements));
}
那我们继续往回走,走到这个 bind() 方法(别走神)
privateT bind(ConfigurationPropertyName name, Bindable target, BindHandler handler, Context context, boolean allowRecursiveBinding, boolean create) { try { // 与刚才一样进入该方法,但此时进入该方法的不是 person 的 Bindable,而是其属性的 Bindable Bindable replacementTarget = handler.onStart(name, target, context); if (replacementTarget == null) { return handleBindResult(name, target, handler, context, null, create); } target = replacementTarget; Object bound = bindObject(name, target, handler, context, allowRecursiveBinding); return handleBindResult(name, target, handler, context, bound, create); } catch (Exception ex) { return handleBindError(name, target, handler, context, ex); } }
@Override publicBindable onStart(ConfigurationPropertyName name, Bindable target, BindContext context) { // 这个属性当然没有被 ConfigurationProperties 注解 ,所以没有增加他的限制属性 NO_DIRECT_PROPERTY(!!) return isConfigurationProperties(target.getType().resolve()) // 直接返回 原对象 ? target.withBindRestrictions(BindRestriction.NO_DIRECT_PROPERTY) : target; }
返回的 Bindable replacementTarget:
真正开始执行 bindObject() 绑定对象
privateObject bindObject(ConfigurationPropertyName name, Bindable target, BindHandler handler, Context context, boolean allowRecursiveBinding) { // 再一次执行此方法,记住,我们之前执行此方法时,是以 person 的身份,判断无效,但此时我们是以 属性的身份 ConfigurationProperty property = findProperty(name, target, context); // .. return bindDataObject(name, target, handler, context, allowRecursiveBinding); }
findProperty() 在此处才发挥了他的作用!(来啦来啦)
privateConfigurationProperty findProperty(ConfigurationPropertyName name, Bindable target, Context context) { // 属性并没有 NO_DIRECT_PROPERTY 的限制,也就是之前所留下的疑惑:为什么有一个限制?导致了我们的person与属性的不同 // 有点组合模式内味了~ if (name.isEmpty() || target.hasBindRestriction(BindRestriction.NO_DIRECT_PROPERTY)) { return null; } // 开始获取配置文件的数据 // 又是不断遍历,从当前上下文中获取 ConfigurationPropertySource , ConfigurationProperty 的资源类 for (ConfigurationPropertySource source : context.getSources()) { // 获取 对应的属性 ConfigurationProperty property = source.getConfigurationProperty(name); if (property != null) { // 返回属性 return property; } } return null; }
其实就是这个嘛,之前见过 就 Orign****
进入 getConfigurationProperty()
@Override
public ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) {
if (name == null) {
return null;
}
// 遍历 PropertyMapper :用于提供PropertySource和ConfigurationPropertySource之间映射的策略
for (PropertyMapper mapper : this.mappers) {
try {
// 里面其实还做了很多逻辑,比如 mapper 的一些映射规则,一些类型转换等等,不再说明啦~
for (String candidate : mapper.map(name)) {
// 真正获取到的配置文件属性的数据,比如这里age就是18
Object value = getPropertySource().getProperty(candidate);
if (value != null) {
// 获取属性位置信息,比如 class path resource [application.yml] 中的第 2 行 第7 个字段
Origin origin = PropertySourceOrigin.get(getPropertySource(), candidate);
// 返回之前做个判空,然后再返回
return ConfigurationProperty.of(name, value, origin);
}
}
}
catch (Exception ex) {
}
}
return null;
}
到这里
ConfigurationProperty 已经封装好我们的属性了
返回到 bindObject()
privateObject bindObject(ConfigurationPropertyName name, Bindable target, BindHandler handler, Context context, boolean allowRecursiveBinding) { ConfigurationProperty property = findProperty(name, target, context); if (property == null && context.depth != 0 && containsNoDescendantOf(context.getSources(), 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); } // .. }
bindProperty()
privateObject bindProperty(Bindable target, Context context, ConfigurationProperty property) { context.setConfigurationProperty(property); Object result = property.getValue(); result = this.placeholdersResolver.resolvePlaceholders(result); result = context.getConverter().convert(result, target); // 经过一系列上下文数据绑定后 返回我们的 属性 的数据 return result; }
于是我们再回到 bind()
privateT bind(ConfigurationPropertyName name, Bindable target, BindHandler handler, Context context, boolean allowRecursiveBinding, boolean create) { try { Bindable replacementTarget = handler.onStart(name, target, context); if (replacementTarget == null) { return handleBindResult(name, target, handler, context, null, create); } target = replacementTarget; // 这里执行完成 bound 就是刚刚的 result Object bound = bindObject(name, target, handler, context, allowRecursiveBinding); // 继续处理这一数据 return handleBindResult(name, target, handler, context, bound, create); } catch (Exception ex) { return handleBindError(name, target, handler, context, ex); } }
handleBindResult():处理绑定结果
privateT handleBindResult(ConfigurationPropertyName name, Bindable target, BindHandler handler, Context context, Object result, boolean create) throws Exception { if (result != null) { result = handler.onSuccess(name, target, context, result); result = context.getConverter().convert(result, target); } if (result == null && create) { result = create(target, context); result = handler.onCreate(name, target, context, result); result = context.getConverter().convert(result, target); Assert.state(result != null, () -> "Unable to create instance for " + target.getType()); } handler.onFinish(name, target, context, result); return context.getConverter().convert(result, target); }
经过一些列回调,转换器处理之后
// 最终处理的转换器
public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
Assert.notNull(targetType, "Target type to convert to cannot be null");
if (sourceType == null) {
Assert.isTrue(source == null, "Source must be [null] if source type == [null]");
return handleResult(null, targetType, convertNullSource(null, targetType));
}
if (source != null && !sourceType.getObjectType().isInstance(source)) {
throw new IllegalArgumentException("Source to convert from must be an instance of [" +
sourceType + "]; instead it was a [" + source.getClass().getName() + "]");
}
GenericConverter converter = getConverter(sourceType, targetType);
if (converter != null) {
// 执行转换
Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
// 返回封装之后的处理结果
return handleResult(sourceType, targetType, result);
}
return handleConverterNotFound(source, sourceType, targetType);
}
然后回到 bind()
privateboolean bind(BeanSupplier beanSupplier, DataObjectPropertyBinder propertyBinder, BeanProperty property) { // 假设是 age // propertyName = age String propertyName = property.getName(); // java.lang.Integer ResolvableType type = property.getType(); // 这个 Supplier 终于有了 age 的一些信息 Supplier
Supplier
此时的 Supplier 已经得到了 bean 的其中一个属性!
往回继续走
privateboolean bind(DataObjectPropertyBinder propertyBinder, Bean bean, BeanSupplier beanSupplier, Context context) { boolean bound = false; for (BeanProperty beanProperty : bean.getProperties().values()) { bound |= bind(beanSupplier, propertyBinder, beanProperty); // 清除一下已经绑定的属性 context.clearConfigurationProperty(); } return bound; }
遍历第二个属性。。
两个属性都绑定成功后
回到我们最初对 person 的 bindDataObject() 方法
继续执行 bindDataObject() , person 对象的属性绑定结束
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 propertyBinder = (propertyName, propertyTarget) -> bind(name.append(propertyName),
propertyTarget, handler, context, false, false);
return context.withDataObject(type, () -> {
for (DataObjectBinder dataObjectBinder : this.dataObjectBinders) {
// 此处返回
Object instance = dataObjectBinder.bind(name, target, context, propertyBinder);
if (instance != null) {
return instance;
}
}
return null;
});
}
回到最初的 withIncreasedDepth()
privateT withIncreasedDepth(Supplier supplier) { increaseDepth(); try { // 终于执行完了此方法 return supplier.get(); } finally { // 此时将 depth-- decreaseDepth(); } }
继续执行返回
privateT withDataObject(Class> type, Supplier supplier) { this.dataObjectBindings.push(type); try { // 返回 return withIncreasedDepth(supplier); } finally { this.dataObjectBindings.pop(); } }
至此 bindDataObject() 返回最终的对象
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 propertyBinder = (propertyName, propertyTarget) -> bind(name.append(propertyName),
propertyTarget, handler, context, false, false);
// 返回
return context.withDataObject(type, () -> {
for (DataObjectBinder dataObjectBinder : this.dataObjectBinders) {
Object instance = dataObjectBinder.bind(name, target, context, propertyBinder);
if (instance != null) {
return instance;
}
}
return null;
});
}
继续完成
privateT bind(ConfigurationPropertyName name, Bindable target, BindHandler handler, Context context, boolean allowRecursiveBinding, boolean create) { try { Bindable replacementTarget = handler.onStart(name, target, context); if (replacementTarget == null) { return handleBindResult(name, target, handler, context, null, create); } target = replacementTarget; Object bound = bindObject(name, target, handler, context, allowRecursiveBinding); // 继续返回 return handleBindResult(name, target, handler, context, bound, create); } catch (Exception ex) { return handleBindError(name, target, handler, context, ex); } }
再执行一次 handleBindResult()
privateT handleBindResult(ConfigurationPropertyName name, Bindable target, BindHandler handler, Context context, Object result, boolean create) throws Exception { if (result != null) { result = handler.onSuccess(name, target, context, result); result = context.getConverter().convert(result, target); } if (result == null && create) { result = create(target, context); result = handler.onCreate(name, target, context, result); result = context.getConverter().convert(result, target); Assert.state(result != null, () -> "Unable to create instance for " + target.getType()); } handler.onFinish(name, target, context, result); return context.getConverter().convert(result, target); }
继续 bind()
publicBindResult bind(ConfigurationPropertyName name, Bindable target, BindHandler handler) { T bound = bind(name, target, handler, false); // 返回 return BindResult.of(bound); }
继续
@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);
}
}
回到最初的 applyBeanPostProcessorsBeforeInitialization()
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 最后后置处理完成的对象
// Person(name=liu, age=18)
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
至此,对 @ConfigurationProperties 注解的源码追踪才算是告一段落
总结太累了,明天继续肝
文章说明文中有一些引用



