Spring Type Conversion(Spring类型转换源码探究)

it2022-05-05  83

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

 

转载于:https://www.cnblogs.com/liuenyuan1996/p/11071845.html


最新回复(0)