1. 程式人生 > >Spring ConversionService 型別轉換(二) ConversionService

Spring ConversionService 型別轉換(二) ConversionService

Spring ConversionService 型別轉換(二) ConversionService

Spring 系列目錄(https://www.cnblogs.com/binarylei/p/10117436.html)

Spring ConversionService 型別轉換系列文章:

  1. Spring ConversionService 型別轉換(一)Converter
  2. Spring ConversionService 型別轉換(二)ConversionService

在上一篇文章中提到了 Spring 3.0 提供了三種類型的轉換器(Converter、ConverterFactory、GenericConverter),分別用來處理 1:1、1:N、N:N 的型別轉換。那肯定要有一個類來統一管理所有的型別轉換器,負責註冊、查詢、轉換等功能,統一對外提供服務,這個類就是 ConversionService。

一、ConversionService 介面說明

ConversionService 類圖

  • 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 {
}

二、DefaultConversionService

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

GenericConversionService 實現了 ConversionService, ConverterRegistry 兩個介面的功能,上面提到的 DefaultConversionService 就是基於 GenericConversionService 的擴充套件,只是註冊了一些預設的轉換器。

3.1 Converters

Converters 是 GenericConversionService 中的內部類,負責所有轉換器的新增、刪除、查詢。轉換器有兩種:一種指定轉換的型別;一種沒有指定,屬於通用的轉換器:

// 全域性通用的轉換器
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 介面。

如果 ConvertiblePair(sourceType 和 targetType) 對應多個轉換器則統一儲存在 ConvertersForPair 中,ConvertersForPair 也是 GenericConversionService 的內部類,它內部維護了一個 LinkedList

(1) add

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

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;
    }
}

3.2 GenericConversionService

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;
}

參考:

  1. 《IOC原始碼-conversionService》:https://www.cnblogs.com/jyyzzjl/p/5478620.html

每天用心記錄一點點。內容也許不重要,但習慣很重要!