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