- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
系列文章:
Spring读源码系列番外篇—01–PropertyValue相关类
Spring读源码系列番外篇—02—PropertyResolver的结构体系剖析—上
Spring读源码系列番外篇—03—PropertyResolver的结构体系剖析—下
Spring读源码系列番外篇—05----类型转换—中
Spirng 3.0全新一代的类型转换机制,它提供的三种类型转换器(Converter、ConverterFactory、GenericConverter),分别可处理1:1、1:N、N:N的类型转换。
按照Spring的设计习惯,必有一个注册中心来统一管理,负责它们的注册、删除等,它就是ConverterRegistry。
另外,内建的绝大多数转换器访问权限都是default/private,那么如何使用它们,以及屏蔽各种转换器的差异化呢?为此,Spring提供了一个统一类型转换服务,它就是ConversionService。
ConverterRegistry和ConversionService的关系密不可分,前者为后者提供转换器管理支撑,后者面向使用者提供服务。本文涉及到的接口/类有:
public interface ConverterRegistry {
//注册一个1:1的转换器----会尝试去参数化类型中提取sourceType和targetType
void addConverter(Converter<?, ?> converter);
//注册一个1:1的转换器----明确sourceType和targetType
<S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter);
//注册一个n:n的转换器
void addConverter(GenericConverter converter);
//注册一个1:n的转化器
void addConverterFactory(ConverterFactory<?, ?> factory);
//移除某个转换器
void removeConvertible(Class<?> sourceType, Class<?> targetType);
}
ConverterRegistry有子接口FormatterRegistry,它属于格式化器的范畴.
面向使用者的统一类型转换服务。换句话说:站在使用层面,你只需要知道ConversionService接口API的使用方式即可,并不需要关心其内部实现机制,可谓对使用者非常友好。
public interface ConversionService {
boolean canConvert(Class<?> sourceType, Class<?> targetType);
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
<T> T convert(Object source, Class<T> targetType);
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
可以看到ConversionService和ConverterRegistry的继承树殊途同归,都直接指向了ConfigurableConversionService这个分支,下面就对它进行介绍
ConversionService和ConverterRegistry的组合接口,自己并未新增任何接口方法。
public interface ConfigurableConversionService extends ConversionService, ConverterRegistry {
}
为什么要先提一嘴这个类呢?当然是因为我们下面要将的GenericConversionService源码中大量使用到了这个类
该类作用很简单,我这里简单介绍一下,就不贴出源码了,毕竟方法挺多的:
private HashMap<Integer, List<String>> myMap;
public void example() {
ResolvableType t = ResolvableType.forField(getClass().getDeclaredField("myMap"));
t.getSuperType(); // AbstractMap<Integer, List<String>>
t.asMap(); // Map<Integer, List<String>>
t.getGeneric(0).resolve(); // Integer
t.getGeneric(1).resolve(); // List
t.getGeneric(1); // List<String>
//第二个泛型,里面的泛型,即List<String>里面的String
t.resolveGeneric(1, 0); // String
}
通过上面这个简单案例应该可以让各位有个大概的了解,这就差不多了,那么我们进入正题吧
我觉得这个类,有空可以参考在自己项目中用用,毕竟算是一个比较方便的工具类
对ConfigurableConversionService接口提供了完整实现的实现类。换句话说:ConversionService和ConverterRegistry接口的功能均通过此类得到了实现,所以它是本文重点。
public class GenericConversionService implements ConfigurableConversionService {
/**
* General NO-OP converter used when conversion is not required.
*
*/
private static final GenericConverter NO_OP_CONVERTER = new NoOpConverter("NO_OP");
/**
* Used as a cache entry when no converter is available.
* This converter is never returned.
*/
private static final GenericConverter NO_MATCH = new NoOpConverter("NO_MATCH");
//Converters是GenericConversionService的内部类,用于管理(添加、删除、查找)转换器们。
//也就说对ConverterRegistry接口的实现最终是委托给它去完成的,它是整个转换服务正常work的内核
private final Converters converters = new Converters();
//它用两个成员变量来管理转换器们,其中converterCache是缓存用于加速查找,因此更为重要的便是Converters喽。
private final Map<ConverterCacheKey, GenericConverter> converterCache = new ConcurrentReferenceHashMap<>(64);
//-------------------------ConverterRegistry注册相关接口的具体实现------------------------
//增加一个1:1的转化器
@Override
public void addConverter(Converter<?, ?> converter) {
//getRequiredTypeInfo是一个工具方法,功能是返回传入converter的具体的泛型参数数组
//泛型参数都被ResolvableType进行包裹,长度为2,一个是原对象类型,一个是目标对象类型
ResolvableType[] typeInfo = getRequiredTypeInfo(converter.getClass(), Converter.class);
//对代理进行判断---这个地方我暂时不清楚,等后面我懂了,就回来完善一下!!!
if (typeInfo == null && converter instanceof DecoratingProxy) {
//这套组合拳目的在于拿到泛型参数数组
typeInfo = getRequiredTypeInfo(((DecoratingProxy) converter).getDecoratedClass(), Converter.class);
}
if (typeInfo == null) {
throw new IllegalArgumentException("Unable to determine source type <S> and target type <T> for your " +
"Converter [" + converter.getClass().getName() + "]; does the class parameterize those types?");
}
//添加转换器----将所有converter都通过ConverterAdapter转换为
addConverter(new ConverterAdapter(converter, typeInfo[0], typeInfo[1]));
}
//和上面那个重载方法相比,少了去解析出convert泛型参数的过程
@Override
public <S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter) {
//这一步和上面那个重载方法一样---这里也用到了适配器模式和上面一样
addConverter(new ConverterAdapter(
converter, ResolvableType.forClass(sourceType), ResolvableType.forClass(targetType)));
}
//上面两个重载方法最终调用的方法--这里参数需要的是GenericConverter
//因为我们之前说过有1:1,1:n,n:n三种转换器,因此我们这边把所有转换器都转换为通用的GenericConverter(n:n)进行管理
@Override
public void addConverter(GenericConverter converter) {
//converters是一个内部类,它管理所有转换器,包括添加、删除、查找。
//这个一会在细聊
this.converters.add(converter);
//清除缓存集合
invalidateCache();
}
//添加一个1:n的转换器
@Override
public void addConverterFactory(ConverterFactory<?, ?> factory) {
//同样因为转换器的泛型参数不确定,因此需要先解析出来
ResolvableType[] typeInfo = getRequiredTypeInfo(factory.getClass(), ConverterFactory.class);
//处理代理问题
if (typeInfo == null && factory instanceof DecoratingProxy) {
typeInfo = getRequiredTypeInfo(((DecoratingProxy) factory).getDecoratedClass(), ConverterFactory.class);
}
if (typeInfo == null) {
throw new IllegalArgumentException("Unable to determine source type <S> and target type <T> for your " +
"ConverterFactory [" + factory.getClass().getName() + "]; does the class parameterize those types?");
}
//ConverterFactoryAdapter是将ConverterFactory转换为通用的GenericAdapter
addConverter(new ConverterFactoryAdapter(factory,
new ConvertiblePair(typeInfo[0].toClass(), typeInfo[1].toClass())));
}
//移除某个转换器
@Override
public void removeConvertible(Class<?> sourceType, Class<?> targetType) {
//可以看出是converters管理某个转换器的删除
this.converters.remove(sourceType, targetType);
//清空缓存
invalidateCache();
}
// ConversionService implementation
@Override
public boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType) {
Assert.notNull(targetType, "Target type to convert to cannot be null");
//将Class包装为TypeDescriptor,然后交给重载方法进行处理
return canConvert((sourceType != null ? TypeDescriptor.valueOf(sourceType) : null),
TypeDescriptor.valueOf(targetType));
}
@Override
public boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
Assert.notNull(targetType, "Target type to convert to cannot be null");
if (sourceType == null) {
return true;
}
//能否进行转换就是去找到有无可用的转换器
//这里如果一开始缓存中没有,那么找到后会加入缓存中,这样一会进行转换的时候,就会直接从缓存中取
//如果找不到也会放入缓存集合--相当于做个标记
GenericConverter converter = getConverter(sourceType, targetType);
return (converter != null);
}
/**
是否不需要进行任何类型转换
*/
public boolean canBypassConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
Assert.notNull(targetType, "Target type to convert to cannot be null");
if (sourceType == null) {
return true;
}
//如果不需要进行任何类型转换,那么getConverter会返回NO_OP_CONVERTER---表示当前类型对不需要进行转换
GenericConverter converter = getConverter(sourceType, targetType);
return (converter == NO_OP_CONVERTER);
}
@Override
@SuppressWarnings("unchecked")
@Nullable
//将source对象转换为targetType类型
public <T> T convert(@Nullable Object source, Class<T> targetType) {
Assert.notNull(targetType, "Target type to convert to cannot be null");
//最终调用的是重载方法来进行处理
return (T) convert(source, TypeDescriptor.forObject(source), TypeDescriptor.valueOf(targetType));
}
@Override
@Nullable
public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
Assert.notNull(targetType, "Target type to convert to cannot be null");
//如果原对象类型为null,那么对应的source对象肯定也为null
if (sourceType == null) {
Assert.isTrue(source == null, "Source must be [null] if source type == [null]");
//convertNullSource:如果targetType是Optional类型,最终返回的是Optional.empty()
//否则返回null
//handleResult:返回第三个参数作为返回结果,如果第三个参数为null,会抛出异常
return handleResult(null, targetType, convertNullSource(null, targetType));
}
//sourceType必须是Source的类型--isInstance---》InstanceOf
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) {
//ConversionUtils.invokeConverter最终就是调用converter的converter方法
Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
//主要对第三个参数是否为空进行校验
return handleResult(sourceType, targetType, result);
}
//source为null,直接返回null,或者target是source的父类,返回直接返回source即可,不需要进行任何类型转换操作
return handleConverterNotFound(source, sourceType, targetType);
}
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor targetType) {
return convert(source, TypeDescriptor.forObject(source), targetType);
}
@Override
public String toString() {
return this.converters.toString();
}
// Protected template methods
@Nullable
protected Object convertNullSource(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
//null--->Optional,那么最终转换后得到的是Optional.empty()
if (targetType.getObjectType() == Optional.class) {
return Optional.empty();
}
return null;
}
@Nullable
protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
//构建缓存key
ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
//先尝试从缓存中去获取
GenericConverter converter = this.converterCache.get(key);
if (converter != null) {
//缓存中存在
//这里提前说一下:如果某个类型对不存在与之关联的转换器,那么在第一次查找无果后
//会在缓存中进行标记,即当前key--->NO_MATCH
//因此如果这里存在转换器,但是为NO_MATCH ,表示不存在对应的转换器可以转换该类型对,返回null即可
return (converter != NO_MATCH ? converter : null);
}
//converters负责通过类型对去查找到指定的转换器
converter = this.converters.find(sourceType, targetType);
//如果找不到
if (converter == null) {
//如果source和target之间是父子关系,那么返回NO_OP_CONVERTER,表示不需要进行类型转换
//否则返回null
converter = getDefaultConverter(sourceType, targetType);
}
//如果到这里找到了对应的转换器,那么会放入缓存中
if (converter != null) {
this.converterCache.put(key, converter);
return converter;
}
//走到这里,说明找不到,那么当前类型对会和一个NO_MATCH的转换器进行关联
this.converterCache.put(key, NO_MATCH);
return null;
}
//如果source和target之间是父子关系,那么返回NO_OP_CONVERTER,表示不需要进行类型转换
//否则返回null
@Nullable
protected GenericConverter getDefaultConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
return (sourceType.isAssignableTo(targetType) ? NO_OP_CONVERTER : null);
}
// ---------------------Internal helpers:内部帮助的方法 ---------------------
@Nullable
private ResolvableType[] getRequiredTypeInfo(Class<?> converterClass, Class<?> genericIfc) {
//对传入的class类进行包装,然后返回包装后的ResolvableType
ResolvableType resolvableType = ResolvableType.forClass(converterClass).as(genericIfc);
//获取此类的泛型参数数组,这些获取到的泛型参数也会被ResolvableType进行包装
ResolvableType[] generics = resolvableType.getGenerics();
if (generics.length < 2) {
return null;
}
//第一个泛型参数为原对象
Class<?> sourceType = generics[0].resolve();
//第二个泛型参数为目标对象
Class<?> targetType = generics[1].resolve();
if (sourceType == null || targetType == null) {
return null;
}
//会返回获取到的泛型数组
return generics;
}
//清除缓存---一般在新增和删除时需要清空缓存
private void invalidateCache() {
this.converterCache.clear();
}
//source为null,直接返回null,或者target是source的父类,返回直接返回source即可,不需要进行任何类型转换操作
@Nullable
private Object handleConverterNotFound(
@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
assertNotPrimitiveTargetType(sourceType, targetType);
return null;
}
if ((sourceType == null || sourceType.isAssignableTo(targetType)) &&
targetType.getObjectType().isInstance(source)) {
return source;
}
throw new ConverterNotFoundException(sourceType, targetType);
}
@Nullable
private Object handleResult(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType, @Nullable Object result) {
if (result == null) {
assertNotPrimitiveTargetType(sourceType, targetType);
}
return result;
}
private void assertNotPrimitiveTargetType(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
if (targetType.isPrimitive()) {
throw new ConversionFailedException(sourceType, targetType, null,
new IllegalArgumentException("A null value cannot be assigned to a primitive type"));
}
}
/**
* 将Converter适配为GenericConverter
*/
@SuppressWarnings("unchecked")
private final class ConverterAdapter implements ConditionalGenericConverter {
//需要进行适配的converter
private final Converter<Object, Object> converter;
//类型对
private final ConvertiblePair typeInfo;
//保存目标对象类型相关信息
private final ResolvableType targetType;
//真正进行适配的地方在ConverterAdapter构造函数这里完成
public ConverterAdapter(Converter<?, ?> converter, ResolvableType sourceType, ResolvableType targetType) {
this.converter = (Converter<Object, Object>) converter;
this.typeInfo = new ConvertiblePair(sourceType.toClass(), targetType.toClass());
this.targetType = targetType;
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(this.typeInfo);
}
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
// Check raw type first...
if (this.typeInfo.getTargetType() != targetType.getObjectType()) {
return false;
}
// Full check for complex generic type match required?
ResolvableType rt = targetType.getResolvableType();
if (!(rt.getType() instanceof Class) && !rt.isAssignableFrom(this.targetType) &&
!this.targetType.hasUnresolvableGenerics()) {
return false;
}
return !(this.converter instanceof ConditionalConverter) ||
((ConditionalConverter) this.converter).matches(sourceType, targetType);
}
@Override
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return convertNullSource(sourceType, targetType);
}
//调用构造函数传入需要进行适配的转化器的convert方法
return this.converter.convert(source);
}
@Override
public String toString() {
return (this.typeInfo + " : " + this.converter);
}
}
/**
将ConverterFactory转化为GenericConverter
*/
@SuppressWarnings("unchecked")
private final class ConverterFactoryAdapter implements ConditionalGenericConverter {
private final ConverterFactory<Object, Object> converterFactory;
private final ConvertiblePair typeInfo;
public ConverterFactoryAdapter(ConverterFactory<?, ?> converterFactory, ConvertiblePair typeInfo) {
this.converterFactory = (ConverterFactory<Object, Object>) converterFactory;
this.typeInfo = typeInfo;
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(this.typeInfo);
}
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
boolean matches = true;
if (this.converterFactory instanceof ConditionalConverter) {
matches = ((ConditionalConverter) this.converterFactory).matches(sourceType, targetType);
}
if (matches) {
Converter<?, ?> converter = this.converterFactory.getConverter(targetType.getType());
if (converter instanceof ConditionalConverter) {
matches = ((ConditionalConverter) converter).matches(sourceType, targetType);
}
}
return matches;
}
@Override
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return convertNullSource(sourceType, targetType);
}
return this.converterFactory.getConverter(targetType.getObjectType()).convert(source);
}
@Override
public String toString() {
return (this.typeInfo + " : " + this.converterFactory);
}
}
/**
缓存key
*/
private static final class ConverterCacheKey implements Comparable<ConverterCacheKey> {
private final TypeDescriptor sourceType;
private final TypeDescriptor targetType;
public ConverterCacheKey(TypeDescriptor sourceType, TypeDescriptor targetType) {
this.sourceType = sourceType;
this.targetType = targetType;
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof ConverterCacheKey)) {
return false;
}
ConverterCacheKey otherKey = (ConverterCacheKey) other;
return (this.sourceType.equals(otherKey.sourceType)) &&
this.targetType.equals(otherKey.targetType);
}
@Override
public int hashCode() {
return (this.sourceType.hashCode() * 29 + this.targetType.hashCode());
}
@Override
public String toString() {
return ("ConverterCacheKey [sourceType = " + this.sourceType +
", targetType = " + this.targetType + "]");
}
@Override
public int compareTo(ConverterCacheKey other) {
int result = this.sourceType.getResolvableType().toString().compareTo(
other.sourceType.getResolvableType().toString());
if (result == 0) {
result = this.targetType.getResolvableType().toString().compareTo(
other.targetType.getResolvableType().toString());
}
return result;
}
}
/**
它管理所有转换器,包括添加、删除、查找。
*/
private static class Converters {
//存取通用的转换器,并不限定转换类型,一般用于兜底
private final Set<GenericConverter> globalConverters = new CopyOnWriteArraySet<>();
//指定了类型对,对应的转换器们的映射关系
//ConvertiblePair:表示一对,包含sourceType和targetType
//ConvertersForPair:这一对对应的转换器们(因为能处理一对的可能存在多个转换器),内部使用一个双端队列Deque来存储,保证顺序
private final Map<ConvertiblePair, ConvertersForPair> converters = new ConcurrentHashMap<>(256);
//添加动作
public void add(GenericConverter converter) {
//先获取当前转换器可以转换的类型对
Set<ConvertiblePair> convertibleTypes = converter.getConvertibleTypes();
if (convertibleTypes == null) {
Assert.state(converter instanceof ConditionalConverter,
"Only conditional converters may return null convertible types");
//如果为空,说明在进行适配前,被适配的转换器并不是 GenericConverter 类型
//那么放入全局集合中
this.globalConverters.add(converter);
}
else {
//类型对和转换器时多对多的关系,通过convertibleTypes方法,我们可以得到一个转换器可以转换的所有类型
//但是我们还需要知道一个类型可以被多少个转换器处理,下面的循环干的就是这个事情
for (ConvertiblePair convertiblePair : convertibleTypes) {
//调用的是返回的ConvertersForPair的add方法
getMatchableConverters(convertiblePair).add(converter);
}
}
}
private ConvertersForPair getMatchableConverters(ConvertiblePair convertiblePair) {
//如果该类型对在converters集合中还不存在,那么会创建一个与当前key关联的ConvertersForPair放入map集合中
return this.converters.computeIfAbsent(convertiblePair, k -> new ConvertersForPair());
}
public void remove(Class<?> sourceType, Class<?> targetType) {
this.converters.remove(new ConvertiblePair(sourceType, targetType));
}
//查找某一个转换器
@Nullable
public GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) {
// Search the full type hierarchy
//getClassHierarchy的作用是啥子呢? 举个栗子:
//getClassHierarchy(User.class)
//class User{}
//返回的集合里面包含User.class和Object.class
//该方法返回的是某个类型的继承树,往上走的
List<Class<?>> sourceCandidates = getClassHierarchy(sourceType.getType());
List<Class<?>> targetCandidates = getClassHierarchy(targetType.getType());
//如果这里想把class User{}转换为class Peo{}
//那么这里会循环四次:
//User--->Peo User-->Object Object--->Peo Object--->Object
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;
}
@Nullable
private GenericConverter getRegisteredConverter(TypeDescriptor sourceType,
TypeDescriptor targetType, ConvertiblePair convertiblePair) {
// Check specifically registered converters
//从转换器集合中寻找某个转换器---这里返回的ConvertersForPair代表能够转换当前类型对的转换器集合
//下面会分析
ConvertersForPair convertersForPair = this.converters.get(convertiblePair);
if (convertersForPair != null) {
//转换器存在
//返回第一个匹配的转换器---因为存在某些转换器虽然可以转换该类型对,但是它实现了ConditionalConverter接口
//还需要调用match进行判断
GenericConverter converter = convertersForPair.getConverter(sourceType, targetType);
if (converter != null) {
return converter;
}
}
//从这里可以看出globalConverter 实现了兜底策略
// Check ConditionalConverters for a dynamic match
for (GenericConverter globalConverter : this.globalConverters) {
if (((ConditionalConverter) globalConverter).matches(sourceType, targetType)) {
return globalConverter;
}
}
return null;
}
//下面的就不分析,感兴趣的自己研究吧
private List<Class<?>> getClassHierarchy(Class<?> type) {
List<Class<?>> hierarchy = new ArrayList<>(20);
Set<Class<?>> visited = new HashSet<>(20);
addToClassHierarchy(0, ClassUtils.resolvePrimitiveIfNecessary(type), false, hierarchy, visited);
boolean array = type.isArray();
int i = 0;
while (i < hierarchy.size()) {
Class<?> candidate = hierarchy.get(i);
candidate = (array ? candidate.getComponentType() : ClassUtils.resolvePrimitiveIfNecessary(candidate));
Class<?> superclass = candidate.getSuperclass();
if (superclass != null && superclass != Object.class && superclass != Enum.class) {
addToClassHierarchy(i + 1, candidate.getSuperclass(), array, hierarchy, visited);
}
addInterfacesToClassHierarchy(candidate, array, hierarchy, visited);
i++;
}
if (Enum.class.isAssignableFrom(type)) {
addToClassHierarchy(hierarchy.size(), Enum.class, array, hierarchy, visited);
addToClassHierarchy(hierarchy.size(), Enum.class, false, hierarchy, visited);
addInterfacesToClassHierarchy(Enum.class, array, hierarchy, visited);
}
addToClassHierarchy(hierarchy.size(), Object.class, array, hierarchy, visited);
addToClassHierarchy(hierarchy.size(), Object.class, false, hierarchy, visited);
return hierarchy;
}
private void addInterfacesToClassHierarchy(Class<?> type, boolean asArray,
List<Class<?>> hierarchy, Set<Class<?>> visited) {
for (Class<?> implementedInterface : type.getInterfaces()) {
addToClassHierarchy(hierarchy.size(), implementedInterface, asArray, hierarchy, visited);
}
}
private void addToClassHierarchy(int index, Class<?> type, boolean asArray,
List<Class<?>> hierarchy, Set<Class<?>> visited) {
if (asArray) {
type = Array.newInstance(type, 0).getClass();
}
if (visited.add(type)) {
hierarchy.add(index, type);
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("ConversionService converters =\n");
for (String converterString : getConverterStrings()) {
builder.append('\t').append(converterString).append('\n');
}
return builder.toString();
}
private List<String> getConverterStrings() {
List<String> converterStrings = new ArrayList<>();
for (ConvertersForPair convertersForPair : this.converters.values()) {
converterStrings.add(convertersForPair.toString());
}
Collections.sort(converterStrings);
return converterStrings;
}
}
/**
* 一个类型对可以被多少个转换器进行处理
*/
private static class ConvertersForPair {
//存放可以转换当前类型对的集合
private final Deque<GenericConverter> converters = new ConcurrentLinkedDeque<>();
public void add(GenericConverter converter) {
this.converters.addFirst(converter);
}
//返回第一个匹配的转换器
@Nullable
public GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
for (GenericConverter converter : this.converters) {
//如果是ConditionalGenericConverter类型的转换器,还需要通过match方法判断当前转换器是否符合转换条件
if (!(converter instanceof ConditionalGenericConverter) ||
((ConditionalGenericConverter) converter).matches(sourceType, targetType)) {
return converter;
}
}
return null;
}
@Override
public String toString() {
return StringUtils.collectionToCommaDelimitedString(this.converters);
}
}
/**
* 当前类型对不需要进行任何类型转换的时候,会返回这个转换器
*/
private static class NoOpConverter implements GenericConverter {
private final String name;
public NoOpConverter(String name) {
this.name = name;
}
@Override
@Nullable
public Set<ConvertiblePair> getConvertibleTypes() {
return null;
}
@Override
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return source;
}
@Override
public String toString() {
return this.name;
}
}
}
如果大家坚持看完了这700多行源码,会发现通用转换器服务类不过如此,其实源码没大家想的那么难
GenericConversionService实现了转换器管理、转换服务的所有功能,是可以直接面向开发者使用的。但是开发者使用时可能并不知道需要注册哪些转换器来保证程序正常运转,Spring并不能要求开发者知晓其内建实现。基于此,Spring在3.1又提供了一个默认实现DefaultConversionService,它对使用者更友好。
Spirng容器默认使用的转换服务实现,继承自GenericConversionService,在其基础行只做了一件事:构造时添加内建的默认转换器们。从而天然具备有了基本的类型转换能力,适用于不同的环境。如:xml解析、@Value解析、http协议参数自动转换等等。
public class DefaultConversionService extends GenericConversionService {
//相信大部分看到他的第一眼,一定认为spring是想实例单例模式,但是事实并非如此,只猜到了一半
@Nullable
private static volatile DefaultConversionService sharedInstance;
/**
构造函数都没有设置成私有,显然印证了上面的分析
*/
public DefaultConversionService() {
//添加很多默认的转换器
addDefaultConverters(this);
}
/**
返回一个共享的默认 ConversionService 实例,在需要时懒惰地构建它。
注意:我们强烈建议为自定义目的构建单独的 ConversionService 实例。
此访问器仅用作需要简单类型强制但无法以任何其他方式访问寿命更长的 ConversionService 实例的代码路径的后备。
*/
public static ConversionService getSharedInstance() {
DefaultConversionService cs = sharedInstance;
//简单的双重锁实现单例模式
if (cs == null) {
synchronized (DefaultConversionService.class) {
cs = sharedInstance;
if (cs == null) {
cs = new DefaultConversionService();
sharedInstance = cs;
}
}
}
return cs;
}
/**
添加适用于大多数环境的转换器。
*/
public static void addDefaultConverters(ConverterRegistry converterRegistry) {
//scalar是标量的意思,这里添加的都是一些和数字相关的转换器
addScalarConverters(converterRegistry);
//添加与集合相关的转换器
addCollectionConverters(converterRegistry);
//JSR310转换器
converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry));
converterRegistry.addConverter(new StringToTimeZoneConverter());
converterRegistry.addConverter(new ZoneIdToTimeZoneConverter());
converterRegistry.addConverter(new ZonedDateTimeToCalendarConverter());
//之前系列讲过的,兜底转换器
converterRegistry.addConverter(new ObjectToObjectConverter());
converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry));
converterRegistry.addConverter(new FallbackObjectToStringConverter());
converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry));
}
public static void addCollectionConverters(ConverterRegistry converterRegistry) {
ConversionService conversionService = (ConversionService) converterRegistry;
converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToArrayConverter(conversionService));
converterRegistry.addConverter(new ArrayToArrayConverter(conversionService));
converterRegistry.addConverter(new CollectionToCollectionConverter(conversionService));
converterRegistry.addConverter(new MapToMapConverter(conversionService));
converterRegistry.addConverter(new ArrayToStringConverter(conversionService));
converterRegistry.addConverter(new StringToArrayConverter(conversionService));
converterRegistry.addConverter(new ArrayToObjectConverter(conversionService));
converterRegistry.addConverter(new ObjectToArrayConverter(conversionService));
converterRegistry.addConverter(new CollectionToStringConverter(conversionService));
converterRegistry.addConverter(new StringToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToObjectConverter(conversionService));
converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService));
converterRegistry.addConverter(new StreamConverter(conversionService));
}
private static void addScalarConverters(ConverterRegistry converterRegistry) {
converterRegistry.addConverterFactory(new NumberToNumberConverterFactory());
converterRegistry.addConverterFactory(new StringToNumberConverterFactory());
converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToCharacterConverter());
converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new NumberToCharacterConverter());
converterRegistry.addConverterFactory(new CharacterToNumberFactory());
converterRegistry.addConverter(new StringToBooleanConverter());
converterRegistry.addConverter(Boolean.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverterFactory(new StringToEnumConverterFactory());
converterRegistry.addConverter(new EnumToStringConverter((ConversionService) converterRegistry));
converterRegistry.addConverterFactory(new IntegerToEnumConverterFactory());
converterRegistry.addConverter(new EnumToIntegerConverter((ConversionService) converterRegistry));
converterRegistry.addConverter(new StringToLocaleConverter());
converterRegistry.addConverter(Locale.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToCharsetConverter());
converterRegistry.addConverter(Charset.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToCurrencyConverter());
converterRegistry.addConverter(Currency.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToPropertiesConverter());
converterRegistry.addConverter(new PropertiesToStringConverter());
converterRegistry.addConverter(new StringToUUIDConverter());
converterRegistry.addConverter(UUID.class, String.class, new ObjectToStringConverter());
}
}
特别强调:转换器的注册顺序非常重要,这决定了通用转换器的匹配结果(谁在前,优先匹配谁,first win)。
JSR310转换器只看到TimeZone、ZoneId等转换,怎么没看见更为常用的LocalDate、LocalDateTime等这些类型转换呢?难道Spring默认是不支持的?
最后,需要特别强调的是:addDefaultConverters是一个静态方法,并且还是public的访问权限,且不仅仅只有本类调用。
实际上,DefaultConversionService仅仅只做了这一件事,所以任何地方只要调用了该静态方法都能达到前者相同的效果,使用上可谓给与了较大的灵活性。
比如Spring Boot环境下不是使用DefaultConversionService而是ApplicationConversionService,后者是对FormattingConversionService扩展,这个话题放在后面详解。
Spring Boot在web环境默认向容器注册了一个WebConversionService,因此你有需要可直接@Autowired使用
顾名思义,它是用于产生ConversionService类型转换服务的工厂Bean,为了方便和Spring容器整合而使用。
因为该类源码中出现了ConversionServiceFactory,并且这个类源码很短,我就直接贴出来讲一下:
public final class ConversionServiceFactory {
private ConversionServiceFactory() {
}
/**
* 将传入的自定义转换器都注册到注册中心里面去
*/
public static void registerConverters(@Nullable Set<?> converters, ConverterRegistry registry) {
if (converters != null) {
//下面操作就不多说了,这里registry调用的方法都是GenericConversionService类中的
for (Object converter : converters) {
if (converter instanceof GenericConverter) {
registry.addConverter((GenericConverter) converter);
}
else if (converter instanceof Converter<?, ?>) {
registry.addConverter((Converter<?, ?>) converter);
}
else if (converter instanceof ConverterFactory<?, ?>) {
registry.addConverterFactory((ConverterFactory<?, ?>) converter);
}
else {
throw new IllegalArgumentException("Each converter object must implement one of the " +
"Converter, ConverterFactory, or GenericConverter interfaces");
}
}
}
}
}
//负责生产ConversionService的bean工厂
public class ConversionServiceFactoryBean implements FactoryBean<ConversionService>, InitializingBean {
//自定义转换器集合
@Nullable
private Set<?> converters;
//通用的转换器类---上面分析过
@Nullable
private GenericConversionService conversionService;
/**
调用此方法,可以向注册中心注册自定义的转换器
*/
public void setConverters(Set<?> converters) {
this.converters = converters;
}
//因为该类实现了InitializingBean接口,因此需要重写该方法,在bean属性被设置后,会回调该接口
@Override
public void afterPropertiesSet() {
//创建默认的转换器服务
this.conversionService = createConversionService();
//注册自定义转换器,ConversionServiceFactory这个类上面分析过
ConversionServiceFactory.registerConverters(this.converters, this.conversionService);
}
protected GenericConversionService createConversionService() {
return new DefaultConversionService();
}
// implementing FactoryBean---实现FactoryBean的接口
@Override
@Nullable
public ConversionService getObject() {
return this.conversionService;
}
@Override
public Class<? extends ConversionService> getObjectType() {
return GenericConversionService.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
这里只有两个信息量需要关注:
我正在尝试编写一个相当多态的库。我遇到了一种更容易表现出来却很难说出来的情况。它看起来有点像这样: {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE
谁能解释一下这个表达式是如何工作的? type = type || 'any'; 这是否意味着如果类型未定义则使用“任意”? 最佳答案 如果 type 为“falsy”(即 false,或 undef
我有一个界面,在IAnimal.fs中, namespace Kingdom type IAnimal = abstract member Eat : Food -> unit 以及另一个成功
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: What is the difference between (type)value and type(va
在 C# 中,default(Nullable) 之间有区别吗? (或 default(long?) )和 default(long) ? Long只是一个例子,它可以是任何其他struct类型。 最
假设我有一个案例类: case class Foo(num: Int, str: String, bool: Boolean) 现在我还有一个简单的包装器: sealed trait Wrapper[
这个问题在这里已经有了答案: Create C# delegate type with ref parameter at runtime (1 个回答) 关闭 2 年前。 为了即时创建委托(dele
我正在尝试获取图像的 dct。一开始我遇到了错误 The function/feature is not implemented (Odd-size DCT's are not implemented
我正在尝试使用 AFNetworking 的 AFPropertyListRequestOperation,但是当我尝试下载它时,出现错误 预期的内容类型{( “应用程序/x-plist” )}, 得
我在下面收到错误。我知道这段代码的意思,但我不知道界面应该是什么样子: Element implicitly has an 'any' type because index expression is
我尝试将 SignalType 从 ReactiveCocoa 扩展为自定义 ErrorType,代码如下所示 enum MyError: ErrorType { // .. cases }
我无法在任何其他问题中找到答案。假设我有一个抽象父类(super class) Abstract0,它有两个子类 Concrete1 和 Concrete1。我希望能够在 Abstract0 中定义类
我想知道为什么这个索引没有用在 RANGE 类型中,而是用在 INDEX 中: 索引: CREATE INDEX myindex ON orders(order_date); 查询: EXPLAIN
我正在使用 RxJava,现在我尝试通过提供 lambda 来订阅可观察对象: observableProvider.stringForKey(CURRENT_DELETED_ID) .sub
我已经尝试了几乎所有解决问题的方法,其中包括。为 提供类型使用app.use(express.static('public'))还有更多,但我似乎无法为此找到解决方案。 index.js : imp
以下哪个 CSS 选择器更快? input[type="submit"] { /* styles */ } 或 [type="submit"] { /* styles */ } 只是好
我不知道这个设置有什么问题,我在 IDEA 中获得了所有注释(@Controller、@Repository、@Service),它在行号左侧显示 bean,然后转到该 bean。 这是错误: 14-
我听从了建议 registering java function as a callback in C function并且可以使用“简单”类型(例如整数和字符串)进行回调,例如: jstring j
有一些 java 类,加载到 Oracle 数据库(版本 11g)和 pl/sql 函数包装器: create or replace function getDataFromJava( in_uLis
我已经从 David Walsh 的 css 动画回调中获取代码并将其修改为 TypeScript。但是,我收到一个错误,我不知道为什么: interface IBrowserPrefix { [
我是一名优秀的程序员,十分优秀!