• Spring ConversionService 类型转换(二) ConversionService


    Spring ConversionService 类型转换(二) ConversionService

    Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.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 converters 数组。

    (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

    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    ssm框架整合入门系列——删除-员工的删除
    ssm框架整合入门系列——修改-员工的修改
    git新建分支并推送至远程仓库库
    想带你去火星看日出
    offsetTop无法获取目标display为none的值
    Vue axios 读取api.github.com展示用户信息
    ssm框架整合入门系列——新增-员工的添加
    课时10:列表:一个打了激素的数组1
    课时9:了不起的分支和循环3
    课时8:了不起的分支和循环2
  • 原文地址:https://www.cnblogs.com/binarylei/p/10263589.html
Copyright © 2020-2023  润新知