上次自己留的坑,自己填一下吧。
PRE
S -> Source
T -> Target
KeySPI
Converter
1 2 3 4 5 package org.springframework.core.convert.converter;public interface Converter <S, T> { T convert (S source) ; }
从名称就能很轻易的看出,这是最基础的从 S -> T. 这点应该和Spring学习。对比我喜欢用A -> B
的确不如Spring的 Soruce 和 Target 专业。细节处应该好好学(doge:)。大家都是写Java的,至于用法,就不用细说。
ConverterFactory
1 2 3 4 5 package org.springframework.core.convert.converter;public interface ConverterFactory <S, R> { <T extends R > Converter<S, T> getConverter (Class<T> targetType) ; }
这个从ConverterFactory貌似看不出来啥,核心是 <T extends R> 这个返回值,说明最终得到的是 R的SubClass。用法可以参考 StringToEnumConverterFactory 这个类.核心是因为传入T的实际类型,可以通过反射做些什么,大部分都用在枚举中,其他场景使用很少。
GenericConverter
1 2 3 4 5 6 package org.springframework.core.convert.converter;public interface GenericConverter { public Set<ConvertiblePair> getConvertibleTypes () ; Object convert (Object source, TypeDescriptor sourceType, TypeDescriptor targetType) ; }
GenericConverter如官网所言 When you require a sophisticated Converter implementation, consider the GenericConverter interface.
当我们需要复杂些的实现的时候可以考虑,这个实现是多种转换的聚合。
ConditionalGenericConverter
1 2 3 4 public interface ConditionalGenericConverter extends GenericConverter , ConditionalConverter { boolean matches (TypeDescriptor sourceType, TypeDescriptor targetType) ; }
如名所见,满足Source 和 TargetType 的条件。至于 TypeDescriptor 可以看作成S和T的包装类。
ConversionService
1 2 3 4 5 6 7 8 9 package org.springframework.core.convert;public interface ConversionService { boolean canConvert (Class<?> sourceType, Class<?> targetType) ; <T> T convert (Object source, Class<T> targetType) ; boolean canConvert (TypeDescriptor sourceType, TypeDescriptor targetType) ; Object convert (Object source, TypeDescriptor sourceType, TypeDescriptor targetType) ; }
终于我们得到了最终的SPI,从SPI中我们就看出来,前两个接口是普通的 S -> T,下面两个增加了ConditionalGenericConverter中的条件转换。
到这里Spring的核心SPI就结束了,官方文档也就说了这么多,那下面进行我们自己的探秘,文档不写的东西,让我们都去代码里面找答案。
SPI 实现
DefaultConversionService.java 是Spring的默认标准实现,我们从这个类开始看起。
先立FLAG,根据我对源码的了解,肯定有一个类似于keyCovertInstantConcurrentHashMap 的东西作为一个核心容器。
看代码,老司机告诉你们一个真理,从第一行往下看是不明智的,从调用端入口看,那才是明智之选。
所以我们先从convert这个最核心的方法看起来。
1 2 3 4 5 6 public class GenericConversionService implements ConfigurableConversionService { public <T> T convert (Object source, Class<T> targetType) { Assert.notNull(targetType, "targetType to convert to cannot be null" ); return (T) convert(source, TypeDescriptor.forObject(source), TypeDescriptor.valueOf(targetType)); } }
这就是DefaultConversionService的Convert的入口,从这里,我们一步一步的深入核心,然后我们可以发现,代码的流向是
convert() -> getConverter() -> this.converters.find(sourceType, targetType)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public GenericConverter find (TypeDescriptor sourceType, TypeDescriptor targetType) { 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 ; }
Bingo,我们最终发现一个非常重要的东西getRegisteredConverter()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private GenericConverter getRegisteredConverter (TypeDescriptor sourceType, TypeDescriptor targetType, ConvertiblePair convertiblePair) { ConvertersForPair convertersForPair = this .converters.get(convertiblePair); if (convertersForPair != null ) { GenericConverter converter = convertersForPair.getConverter(sourceType, targetType); if (converter != null ) { return converter; } } for (GenericConverter globalConverter : this .globalConverters) { if (((ConditionalConverter) globalConverter).matches(sourceType, targetType)) { return globalConverter; } } return null ; }
从代码上,我们就发现了,this.converters 和 this.globalConverters 这两个就是整个转换的核心所在。
看下比较核心的converters的声明
1 2 3 private final Set<GenericConverter> globalConverters = new LinkedHashSet <GenericConverter>();private final Map<ConvertiblePair, ConvertersForPair> converters = new LinkedHashMap <ConvertiblePair, ConvertersForPair>(36 );
上面立的那个Flag算是成功了解围了,的确是一个HashMap,不过实际是一个LinkedHashMap。
那我继续看啊···ConvertiblePair是个什么鬼东西
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 final class ConvertiblePair { private final Class<?> sourceType; private final Class<?> targetType; public ConvertiblePair (Class<?> sourceType, Class<?> targetType) { Assert.notNull(sourceType, "Source type must not be null" ); Assert.notNull(targetType, "Target type must not be null" ); this .sourceType = sourceType; this .targetType = targetType; } @Override public int hashCode () { return (this .sourceType.hashCode() * 31 + this .targetType.hashCode()); } }
那我们找到了这个Key,这个设计,正如我之前变色龙中所声明 ConvertKey 极为的类似。
不过Spring的Value就是复杂了些,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 private static class ConvertersForPair { private final LinkedList<GenericConverter> converters = new LinkedList <GenericConverter>(); public void add (GenericConverter converter) { this .converters.addFirst(converter); } public GenericConverter getConverter (TypeDescriptor sourceType, TypeDescriptor targetType) { for (GenericConverter converter : this .converters) { if (!(converter instanceof ConditionalGenericConverter) || ((ConditionalGenericConverter) converter).matches(sourceType, targetType)) { return converter; } } return null ; } }
我们从这里getConverter方法,可以看出,通过S和T的类型描述去获得真正的转换器。举个例子
1 2 DefaultConversionService defaultConversionService = new DefaultConversionService ();defaultConversionService.convert("1" , Integer.class);
这里最后会调用的是 StringToNumber 这个 Converter。