Spring-convert-(基本结构)

上次自己留的坑,自己填一下吧。

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 的东西作为一个核心容器。

Flag

看代码,老司机告诉你们一个真理,从第一行往下看是不明智的,从调用端入口看,那才是明智之选。
所以我们先从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) {
// 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;
}

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) {

// Check specifically registered converters
ConvertersForPair convertersForPair = this.converters.get(convertiblePair);
if (convertersForPair != null) {
GenericConverter converter = convertersForPair.getConverter(sourceType, targetType);
if (converter != null) {
return converter;
}
}
// Check ConditionalConverters for a dynamic match
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。