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
Spring Type Conversion(Spring类型转换源码探究)的更多相关文章
- Spring Type Conversion(Spring类型转换)
Spring Type Conversion(Spring类型转换) 1:概述: Spring3引入了core.convert包,提供了通用类型转换系统,定义了实现类型转换和运行时执行类型的SPI. ...
- Mybatis的初始化和结合Spring Framework后初始化的源码探究
带着下面的问题进行学习: (1)Mybatis 框架或 Spring Framework 框架对数据层 Mapper 接口做了代理,那是做了 JDK 动态代理还是 CGLIB 代理? (2)Mappe ...
- Mybatis一级缓存和结合Spring Framework后失效的源码探究
1.在下面的案例中,执行两次查询控制台只会输出一次 SQL 查询: mybatis-config.xml <?xml version="1.0" encoding=" ...
- Spring Framework自动装配setAutowireMode和Mybatis案例的源码探究
由前文可得知, Spring Framework的自动装配有两种方式:xml配置和注解配置: 自动装配的类型有: (1)xml配置中的byType根据类型查找(@Autowired注解是默认根据类型查 ...
- Spring Environment(二)源码分析
Spring Environment(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Envi ...
- 七、Spring之深入理解AOP源码
Spring之深入理解AOP源码 在上一篇博文中,我们对AOP有了初步的了解,那么接下来我们就对AOP的实现原理进行深入的分析. 在之前写的那个AOP示例代码当中有这样一个注解:@Enable ...
- Spring框架之spring-web http源码完全解析
Spring框架之spring-web http源码完全解析 Spring-web是Spring webMVC的基础,由http.remoting.web三部分组成. http:封装了http协议中的 ...
- Spring框架之spring-web web源码完全解析
Spring框架之spring-web web源码完全解析 spring-web是Spring webMVC的基础,由http.remoting.web三部分组成,核心为web模块.http模块封装了 ...
- 一文读懂Spring动态配置多数据源---源码详细分析
Spring动态多数据源源码分析及解读 一.为什么要研究Spring动态多数据源 期初,最开始的原因是:想将答题服务中发送主观题答题数据给批改中间件这块抽象出来, 但这块主要使用的是mq消息的方式 ...
随机推荐
- WPF 高速书写 StylusPlugIn 原理
原文:WPF 高速书写 StylusPlugIn 原理 本文告诉大家 WPF 的 StylusPlugIn 为什么能做高性能书写,在我的上一篇博客和大家介绍了 WPF 的触摸原理,但是没有详细告诉大家 ...
- Spring+SpringMVC+MyBatis+easyUI
Spring+SpringMVC+MyBatis+easyUI 日常啰嗦 还好在第一篇文章里就列好了接下来的主线及要写的知识点,不然都不知道要写什么东西了,开篇里已经列了基础篇要讲svn和git的知识 ...
- oracle的number的浅析
author:skate time:2011-02-14 oracle的number的浅析 从例如以下几个方面来认识number 1.表示的数值范围 2.占用的存储空间 3.number的性能 ...
- LVS实现负载均衡原理及安装配置
LVS实现负载均衡原理及安装配置 负载均衡集群是 load balance 集群的简写,翻译成中文就是负载均衡集群.常用的负载均衡开源软件有nginx.lvs.haproxy,商业的硬件负载均衡设备F ...
- 将git文件挂到cdn上
网址:http://raw.githack.com/
- hdu 3966 树链分割第一3遍
真的不好意思说话.你写得越多,对风暴各种问题泄露,更离谱,有什么错有.. .但是,仍然有一个.同时经过规范的编写清晰的代码.不能认为是理所当然... 树桩阵列版: #include<cstdio ...
- 制作WPF时钟之2
原文:制作WPF时钟之2 前段时间写了一篇"制作简单的WPF时钟",今天再制作了一个更漂亮的WPF时钟,目前仅完成了设计部分,准备将它制作成一个无边框窗体式的时钟. 效果图: ...
- Python抓取小说
Python抓取小说 前言 这个脚本命令MAC在抓取小说写,使用Python它有几个码. 代码 # coding=utf-8 import re import urllib2 import chard ...
- INCORRECT PERMISSIONS ON /USR/LIB/PO1KIT-AGENT-HELPER-1(NEEDS TO BE SETUID ROOT)
INCORRECT PERMISSIONS ON /USR/LIB/PO1KIT-AGENT-HELPER-1(NEEDS TO BE SETUID ROOT) # sudo chmod +s /us ...
- WPF特效-拼图游戏
原文:WPF特效-拼图游戏 此文主要描述我实现碎片化的便捷过程. 步骤1: 选取参考图如下(百度图库搜的): 步骤2: 根据效果图或者模型构建贝塞尔曲线,为了方便查看效果,可以设置控制点, ...