作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
学习必须往深处挖,挖的越深,基础越扎实!
阶段1、深入多线程
阶段2、深入多线程设计模式
阶段3、深入juc源码解析
码哥源码部分
码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】
码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】
码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】
码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】
打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】
createAttributeFromRequestValue
上篇说道,我们从请求参数里获得了属性值,但是是String类型的,而我们的参数需要是int的,所以这里会有一个绑定和转换的过程,我们来看看是怎么做的。
数据绑定器初始化
在创建数据绑定器WebDataBinder后,会进行初始化,也就是让数据绑定工厂的所有绑定方法来执行一遍,因为绑定方法那么多,不知道哪个是可以绑定上的,所以要遍历执行,先看能不能满足条件,满足条件的话就执行绑定方法,所以这里如果有很多的话,也不太会有太大的性能问题,因为可能只有一个能绑定上,甚至没有,只是会判断绑定的条件是否符合isBinderMethodApplicable。

参数如何符合绑定方法呢
其实就是获取绑定方法上的InitBinder的注解属性值,其实就是参数ModelAttribute注解的属性名字符串数组,如果没有写名字,就是空字符串数组。如果InitBinder没写属性名,那就表示无条件符合,就会执行绑定方法,如果写了属性名,那会判断参数的属性名是否存在其中,存在才算满足。

遍历每一个属性名,进行比较,只要有满足的就可以了:

什么样的可以被无条件通过呢,就是一些全局的绑定方法,比如日期转换,好像这个方法老执行,是不是耗性能啊,其实不是,你看这个方法是有参数传进来的,是绑定到这个参数上,也就是数据绑定器上的:

数据转换
绑定器初始化完成后要进行数据的转换啦,先把属性值类型和参数类型封装成TypeDescriptor,然后判断是否可以转换,最后尝试转换。

如何判断是否可转换
当然是尝试获得转换器啦:

getConverter
还是老套路,先缓存,然后遍历,找到后方缓存,没找到就放NoOpConverter对象,表示这个类型不能转换。
@Nullable
protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
GenericConverter converter = this.converterCache.get(key);//缓存中取
if (converter != null) {
return (converter != NO_MATCH ? converter : null);
}
converter = this.converters.find(sourceType, targetType);//遍历所有的转换器取
if (converter == null) {
converter = getDefaultConverter(sourceType, targetType);
}
if (converter != null) {
this.converterCache.put(key, converter);//放入缓存
return converter;
}
this.converterCache.put(key, NO_MATCH);
return null;
}
GenericConversionService的find从所有转换器中寻找
具体他会获取两个类型的所有父类,依次封装成ConvertiblePair对象,然后进行转换器获取,因为转换器是个映射,键就是ConvertiblePair对象。这里按照层级归类的,先进行子类判断,最后再到父类。
@Nullable
public GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) {
// Search the full type hierarchy
List<Class<?>> sourceCandidates = getClassHierarchy(sourceType.getType());
List<Class<?>> targetCandidates = getClassHierarchy(targetType.getType());
for (Class<?> sourceCandidate : sourceCandidates) {
for (Class<?> targetCandidate : targetCandidates) {
ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate);
GenericConverter converter = getRegisteredConverter(sourceType, targetType, convertiblePair);
if (converter != null) {
return converter;
}
}
}
return null;
}
getRegisteredConverter
关键就是这里啦,converters是初始化的时候就创建的,而且把转换器都放进去了,是个Map<ConvertiblePair, ConvertersForPair>映射。所以知道为什么前面要封装成ConvertersForPair对象了吧,为了这里快速获取。获取ConvertersForPair之后在从里面获取对应的转换器,如果获取不到就从全局里获取。

转换器找到了,我们下篇说说怎么转换吧。
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。
深入解析:多线程与数据绑定技术原理与Java源码探索,
632

被折叠的 条评论
为什么被折叠?



