Spring 系列目錄(http://www.javashuo.com/article/p-kqecupyl-bm.html)html
Spring ConversionService 類型轉換系列文章:java
在上一篇文章中提到了 Spring 3.0 提供了三種類型的轉換器(Converter、ConverterFactory、GenericConverter),分別用來處理 1:一、1:N、N:N 的類型轉換。那確定要有一個類來統一管理全部的類型轉換器,負責註冊、查找、轉換等功能,統一對外提供服務,這個類就是 ConversionService。spring
ConversionService
類型轉換。ConverterRegistry
轉換器註冊、刪除、查找功能。ConfigurableConversionService
集合了上面兩個接口的功能。GenericConversionService
實現了 ConfigurableConversionService 接口,Spring 使用的 ConversionService 都是基於這個類的擴展。DefaultConversionService
擴展 GenericConversionService,註冊了一批默認的轉換器。// 類型轉換 public interface ConversionService { boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType); boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType); <T> T convert(@Nullable Object source, Class<T> targetType); Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType); } // 三種類型的轉換器的添加和刪除 public interface ConverterRegistry { void addConverter(Converter<?, ?> converter); <S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter); void addConverter(GenericConverter converter); void addConverterFactory(ConverterFactory<?, ?> factory); void removeConvertible(Class<?> sourceType, Class<?> targetType); } public interface ConfigurableConversionService extends ConversionService, ConverterRegistry { }
ConversionService 有一個默認的實現 DefaultConversionService,這個類在初始化時會添加 Spring 默認的轉換器,大部分時候使用這個實現就能夠完成所須要的功能。數組
public DefaultConversionService() { addDefaultConverters(this); } // DefaultConversionService 惟一的功能就是註冊默認的轉換器 public static void addDefaultConverters(ConverterRegistry converterRegistry) { // 1. 基礎的標準轉換器 addScalarConverters(converterRegistry); // 2. 集合類型 addCollectionConverters(converterRegistry); // 3. 其餘擴展 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)); }
GenericConversionService 實現了 ConversionService, ConverterRegistry 兩個接口的功能,上面提到的 DefaultConversionService 就是基於 GenericConversionService 的擴展,只是註冊了一些默認的轉換器。緩存
Converters 是 GenericConversionService 中的內部類,負責全部轉換器的添加、刪除、查找。轉換器有兩種:一種指定轉換的類型;一種沒有指定,屬於通用的轉換器:ide
// 全局通用的轉換器 private final Set<GenericConverter> globalConverters = new LinkedHashSet<>(); // 指定轉換類型的轉換器,ConvertiblePair 是 GenericConverter 接口的內部類,包含 sourceType 和 targetType private final Map<ConvertiblePair, ConvertersForPair> converters = new LinkedHashMap<>(36);
對於三種轉換器 Converter、ConverterFactory、GenericConverter 在添加到 Converters 中時都會進行適配成 GenericConverter,方便統一管理。這兩個適配器都是 GenericConversionService 的內部類,ConverterAdapter 和 ConverterFactoryAdapter 都實現了 ConditionalGenericConverter 接口。ui
若是 ConvertiblePair(sourceType 和 targetType) 對應多個轉換器則統一存儲在 ConvertersForPair 中,ConvertersForPair 也是 GenericConversionService 的內部類,它內部維護了一個 LinkedList
(1) add3d
public void add(GenericConverter converter) { Set<ConvertiblePair> convertibleTypes = converter.getConvertibleTypes(); // 1. globalConverters,沒有指定 convertibleTypes 則根據 ConditionalConverter#matches 匹配 if (convertibleTypes == null) { Assert.state(converter instanceof ConditionalConverter, "Only conditional converters may return null convertible types"); this.globalConverters.add(converter); // 2. converters,指定 convertibleTypes } else { for (ConvertiblePair convertiblePair : convertibleTypes) { ConvertersForPair convertersForPair = this.converters.get(convertiblePair); if (convertersForPair == null) { convertersForPair = new ConvertersForPair(); this.converters.put(convertiblePair, convertersForPair); } convertersForPair.add(converter); } } }
(2) removecode
public void remove(Class<?> sourceType, Class<?> targetType) { this.converters.remove(new ConvertiblePair(sourceType, targetType)); }
(3) find
public GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) { // 獲取 sourceType 類的全部父類和接口 List<Class<?>> sourceCandidates = getClassHierarchy(sourceType.getType()); // 獲取 targetType 類的全部父類和接口 List<Class<?>> targetCandidates = getClassHierarchy(targetType.getType()); for (Class<?> sourceCandidate : sourceCandidates) { for (Class<?> targetCandidate : targetCandidates) { ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate); // 查找指定 sourceType, targetType, convertiblePair 的轉換器 GenericConverter converter = getRegisteredConverter(sourceType, targetType, convertiblePair); if (converter != null) { return converter; } } } return null; } private GenericConverter getRegisteredConverter(TypeDescriptor sourceType, TypeDescriptor targetType, ConvertiblePair convertiblePair) { // 1. 首先在 converters 中查找 ConvertersForPair convertersForPair = this.converters.get(convertiblePair); if (convertersForPair != null) { GenericConverter converter = convertersForPair.getConverter(sourceType, targetType); if (converter != null) { return converter; } } // 2. 再在 globalConverters 中查找 for (GenericConverter globalConverter : this.globalConverters) { if (((ConditionalConverter) globalConverter).matches(sourceType, targetType)) { return globalConverter; } } return null; }
ConvertersForPair 根據 sourceType 和 targetType 查找可用的 GenericConverter
private static class ConvertersForPair { private final LinkedList<GenericConverter> converters = new LinkedList<>(); public void add(GenericConverter converter) { this.converters.addFirst(converter); } // 取第一個匹配到的 GenericConverter 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; } }
GenericConversionService 內部有兩個屬性
// Converters 負責全部轉換器的添加、刪除、查找,上面已經說了 private final Converters converters = new Converters(); // 緩存已經匹配事後 GenericConverter,避免下次還要查找 private final Map<ConverterCacheKey, GenericConverter> converterCache = new ConcurrentReferenceHashMap<>(64);
(1) 添加
// Converter public void addConverter(Converter<?, ?> converter) { ResolvableType[] typeInfo = getRequiredTypeInfo(converter.getClass(), Converter.class); addConverter(new ConverterAdapter(converter, typeInfo[0], typeInfo[1])); } // ConverterFactory public void addConverterFactory(ConverterFactory<?, ?> factory) { ResolvableType[] typeInfo = getRequiredTypeInfo(factory.getClass(), ConverterFactory.class); addConverter(new ConverterFactoryAdapter(factory, new ConvertiblePair(typeInfo[0].toClass(), typeInfo[1].toClass()))); } // GenericConverter public void addConverter(GenericConverter converter) { this.converters.add(converter); // 清空 converterCache 緩存中的數據 invalidateCache(); }
添加的操做很是簡單,在添加以前先要解析 Converter 或 ConverterFactory 的源類型和目標類型,由 getRequiredTypeInfo 完成。
private ResolvableType[] getRequiredTypeInfo(Class<?> converterClass, Class<?> genericIfc) { ResolvableType resolvableType = ResolvableType.forClass(converterClass).as(genericIfc); 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; }
(2) 查找
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); } // 1. 委託給 converters 完成 converter = this.converters.find(sourceType, targetType); // 2. 由子類重寫,默認判斷 sourceType 和 targetType 的類型 // 如不須要轉換(targetType 是 sourceType 的子類),直接返回 source 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; }
查找其實也很簡單,核心步驟 converters.find() 都委託給 converters 完成了。
(3) canConvert
@Override public boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType) { Assert.notNull(targetType, "Target type to convert to cannot be null"); 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); }
(4) convert
@Override 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 public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) { Assert.notNull(targetType, "Target type to convert to cannot be null"); // 1. sourceType==null && source==null,返回 null(Optional) if (sourceType == null) { Assert.isTrue(source == null, "Source must be [null] if source type == [null]"); return handleResult(null, targetType, convertNullSource(null, targetType)); } // 2.1. getConverter 獲取轉換器 GenericConverter converter = getConverter(sourceType, targetType); if (converter != null) { // 2.2. 執行 converter#convert 方法 Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType); return handleResult(sourceType, targetType, result); } return handleConverterNotFound(source, sourceType, targetType); }
至於 handleResult 和 handleConverterNotFound 就很是簡單了
private Object handleResult(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType, @Nullable Object result) { if (result == null) { assertNotPrimitiveTargetType(sourceType, targetType); } return result; }
參考:
天天用心記錄一點點。內容也許不重要,但習慣很重要!