zoukankan      html  css  js  c++  java
  • Spring Type Conversion(Spring类型转换源码探究)

    1:概述

    类型转换系统负责Spring框架中对象类型转换和格式化工作。

    ConversionService默认实现UML图如下所示:

    GenericConversionService(通用类型转换服务),是整个类型转换系统的完整实现。作为容器,

    管理转换器,同时调用这些转换器进行类型转换,是一个空的容器,内部没有任何转换器。是线程安全。

    2:GenericConversionService(通用类型转换服务)学习

    (1):转换器缓存设计

    //自定义Map Key实现
        private final Map<ConverterCacheKey, GenericConverter> converterCache = new ConcurrentReferenceHashMap<>(64);
    ​
        /**
         * Key for use with the converter cache.
         */
        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(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;
            }
        }

    (2):转换器类型适配器设计(适配器模式)

        /**
         * Adapts a {@link Converter} to a {@link GenericConverter}.
         */
        @SuppressWarnings("unchecked")
        private final class ConverterAdapter implements ConditionalGenericConverter {
    
            private final Converter<Object, Object> converter;
    
            private final ConvertiblePair typeInfo;
    
            private final ResolvableType targetType;
    
            public ConverterAdapter(Converter<?, ?> converter, ResolvableType sourceType, ResolvableType targetType) {
                this.converter = (Converter<Object, Object>) converter;
                this.typeInfo = new ConvertiblePair(sourceType.resolve(Object.class), targetType.resolve(Object.class));
                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);
                }
                return this.converter.convert(source);
            }
    
            @Override
            public String toString() {
                return (this.typeInfo + " : " + this.converter);
            }
        }
    
    
        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);
            }
        }

    (3):转换器存储设计

    
    
     private final Converters converters = new Converters();
        
        /**
         * Manages all converters registered with the service.
         */
        private static class Converters {
    ​
            private final Set<GenericConverter> globalConverters = new LinkedHashSet<>();
    ​
            private final Map<ConvertiblePair, ConvertersForPair> converters = new LinkedHashMap<>(36);
        }

    (4):没有操作和没有匹配类型设计

    
    
    /**
         * 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");
    ​
    ​
    ​
            /**
         * Internal converter that performs no operation.
         */
        private static class NoOpConverter implements GenericConverter {
    ​
            private final String name;
    ​
            public NoOpConverter(String name) {
                this.name = name;
            }
    ​
            @Override
            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;
            }
        }

    总结

    • 适配器合理设计

    • 缓存合理设计

    • 存储合理设计

    • 不匹配和不操作合理设计

    • 读操作设计成一个接口(参照ConversionService)

    • 注册操作设计成一个接口(参照ConverterRegistry)

    • 写操作设计成一个接口(参照ConfigurableConversionService)

    (3):DefaultConversionService源码学习

    默认的类型转换系统,继承了GenericConversionService类。在构造方法调用添加默认的转换器。

    public class DefaultConversionService extends GenericConversionService {
    ​
        @Nullable
        private static volatile DefaultConversionService sharedInstance;
    ​
    ​
        /**
         * Create a new {@code DefaultConversionService} with the set of
         * {@linkplain DefaultConversionService#addDefaultConverters(ConverterRegistry) default converters}.
         */
        public DefaultConversionService() {
            addDefaultConverters(this);
        }
    ​
    ​
        /**
         * Return a shared default {@code ConversionService} instance,
         * lazily building it once needed.
         * <p><b>NOTE:</b> We highly recommend constructing individual
         * {@code ConversionService} instances for customization purposes.
         * This accessor is only meant as a fallback for code paths which
         * need simple type coercion but cannot access a longer-lived
         * {@code ConversionService} instance any other way.
         * @return the shared {@code ConversionService} instance (never {@code null})
         * @since 4.3.5
         */
        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;
        }
    }
    ​
    总结
    
    单例模式之双重检锁模式正确运用
    
    (4):ConversionServiceFactoryBean(类型转换器注册工厂Bean)
    
    /**
     * A factory providing convenient access to a ConversionService configured with
     * converters appropriate for most environments. Set the
     * {@link #setConverters "converters"} property to supplement the default converters.
     *
     * <p>This implementation creates a {@link DefaultConversionService}.
     * Subclasses may override {@link #createConversionService()} in order to return
     * a {@link GenericConversionService} instance of their choosing.
     *
     * <p>Like all {@code FactoryBean} implementations, this class is suitable for
     * use when configuring a Spring application context using Spring {@code <beans>}
     * XML. When configuring the container with
     * {@link org.springframework.context.annotation.Configuration @Configuration}
     * classes, simply instantiate, configure and return the appropriate
     * {@code ConversionService} object from a {@link
     * org.springframework.context.annotation.Bean @Bean} method.
     * @since 3.0
     */
    public class ConversionServiceFactoryBean implements FactoryBean<ConversionService>, InitializingBean {
    ​
        @Nullable
        private Set<?> converters;
    ​
        @Nullable
        private GenericConversionService conversionService;
    ​
    ​
        /**
         * Configure the set of custom converter objects that should be added:
         * implementing {@link org.springframework.core.convert.converter.Converter},
         * {@link org.springframework.core.convert.converter.ConverterFactory},
         * or {@link org.springframework.core.convert.converter.GenericConverter}.
         */
        public void setConverters(Set<?> converters) {
            this.converters = converters;
        }
    ​
        @Override
        public void afterPropertiesSet() {
            this.conversionService = createConversionService();
            ConversionServiceFactory.registerConverters(this.converters, this.conversionService);
        }
    ​
        /**
         * Create the ConversionService instance returned by this factory bean.
         * <p>Creates a simple {@link GenericConversionService} instance by default.
         * Subclasses may override to customize the ConversionService instance that
         * gets created.
         */
        protected GenericConversionService createConversionService() {
            return new DefaultConversionService();
        }
    ​
    ​
        // implementing FactoryBean
    ​
        @Override
        @Nullable
        public ConversionService getObject() {
            return this.conversionService;
        }
    ​
        @Override
        public Class<? extends ConversionService> getObjectType() {
            return GenericConversionService.class;
        }
    ​
        @Override
        public boolean isSingleton() {
            return true;
        }
    ​
    }
    ​
    ​
    /**
     * A factory for common {@link org.springframework.core.convert.ConversionService}
     * configurations.
     * @since 3.0
     */
    public abstract class ConversionServiceFactory {
    ​
        /**
         * Register the given Converter objects with the given target ConverterRegistry.
         * @param converters the converter objects: implementing {@link Converter},
         * {@link ConverterFactory}, or {@link GenericConverter}
         * @param registry the target registry
         */
        public static void registerConverters(@Nullable Set<?> converters, ConverterRegistry registry) {
            if (converters != null) {
                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");
                    }
                }
            }
        }
    ​
    }

    总结

    • 简单工厂模式运用

    • FactoryBean使用

    (5):格式化Formatter体系

    总结

    • 往Spring类型转换系统靠.

    (6):DefaultConversionService可支持转换的列表

    格式:sourceType-targetType

    //简单类型

    Number-->Number

    String-->Number Number-->String

    String-->Character Character-->String

    Number-->Character Character-->Number

    String-->Boolean Boolean-->String

    String-->Enum Enum-->String

    Integer-->Enum Enum-->Integer

    String-->Locale Locale-->String

    String-->Charset Charset->String

    String-->Currency(货币) Currency-->String

    String-->Properties Properties-->String

    String-->UUID UUID-->String

    //集合类型和数组类型

    Object[]-->Collection Collection-->Object[]

    Object[]-->Object[]

    Collection-->Collection

    Map-->Map

    Object[]-->String String-->Object[]

    Object[]-->Object Object-->Object[]

    Collection-->String String-->Collection

    Collection-->Object Object-->Collection

    Stream-->Collection Collection-->Stream

    Stream-->Object[] Object[]-->Stream

    //其他类型

    ByteBuffer-->Object Object-->ByteBuffer

    ByteBuffer-->byte[] byte[]-->ByteBuffer

    String-->TimeZone

    ZoneId-->TimeZone

    ZonedDateTime-->Calendar

    Object-->Object

    Object-->String

    Object-->Optional

    Collection-->Optional

    Object[]-->Optional

  • 相关阅读:
    HDU2586 How far away?(tarjan的LCA)
    You Raise Me Up
    POJ2891 Strange Way to Express Integers(中国剩余定理)
    POJ2142 The Balance(扩展欧几里得)
    HDU 1166模仿大牛写的线段树
    NetWord Dinic
    HDU 1754 线段树裸题
    hdu1394 Minimum Inversion Number
    hdu2795 Billboard
    【完全版】线段树
  • 原文地址:https://www.cnblogs.com/liuenyuan1996/p/11071845.html
Copyright © 2011-2022 走看看