1:概述

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

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

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

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

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

(1):转换器缓存设计


  1. //自定义Map Key实现
  2. private final Map<ConverterCacheKey, GenericConverter> converterCache = new ConcurrentReferenceHashMap<>(64);

  3. /**
  4. * Key for use with the converter cache.
  5. */
  6. private static final class ConverterCacheKey implements Comparable<ConverterCacheKey> {

  7. private final TypeDescriptor sourceType;

  8. private final TypeDescriptor targetType;

  9. public ConverterCacheKey(TypeDescriptor sourceType, TypeDescriptor targetType) {
  10. this.sourceType = sourceType;
  11. this.targetType = targetType;
  12. }

  13. @Override
  14. public boolean equals(Object other) {
  15. if (this == other) {
  16. return true;
  17. }
  18. if (!(other instanceof ConverterCacheKey)) {
  19. return false;
  20. }
  21. ConverterCacheKey otherKey = (ConverterCacheKey) other;
  22. return (this.sourceType.equals(otherKey.sourceType)) &&
  23. this.targetType.equals(otherKey.targetType);
  24. }

  25. @Override
  26. public int hashCode() {
  27. return (this.sourceType.hashCode() * 29 + this.targetType.hashCode());
  28. }

  29. @Override
  30. public String toString() {
  31. return ("ConverterCacheKey [sourceType = " + this.sourceType +
  32. ", targetType = " + this.targetType + "]");
  33. }

  34. @Override
  35. public int compareTo(ConverterCacheKey other) {
  36. int result = this.sourceType.getResolvableType().toString().compareTo(
  37. other.sourceType.getResolvableType().toString());
  38. if (result == 0) {
  39. result = this.targetType.getResolvableType().toString().compareTo(
  40. other.targetType.getResolvableType().toString());
  41. }
  42. return result;
  43. }
  44. }

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

  1. /**
  2. * Adapts a {@link Converter} to a {@link GenericConverter}.
  3. */
  4. @SuppressWarnings("unchecked")
  5. private final class ConverterAdapter implements ConditionalGenericConverter {
  6.  
  7. private final Converter<Object, Object> converter;
  8.  
  9. private final ConvertiblePair typeInfo;
  10.  
  11. private final ResolvableType targetType;
  12.  
  13. public ConverterAdapter(Converter<?, ?> converter, ResolvableType sourceType, ResolvableType targetType) {
  14. this.converter = (Converter<Object, Object>) converter;
  15. this.typeInfo = new ConvertiblePair(sourceType.resolve(Object.class), targetType.resolve(Object.class));
  16. this.targetType = targetType;
  17. }
  18.  
  19. @Override
  20. public Set<ConvertiblePair> getConvertibleTypes() {
  21. return Collections.singleton(this.typeInfo);
  22. }
  23.  
  24. @Override
  25. public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
  26. // Check raw type first...
  27. if (this.typeInfo.getTargetType() != targetType.getObjectType()) {
  28. return false;
  29. }
  30. // Full check for complex generic type match required?
  31. ResolvableType rt = targetType.getResolvableType();
  32. if (!(rt.getType() instanceof Class) && !rt.isAssignableFrom(this.targetType) &&
  33. !this.targetType.hasUnresolvableGenerics()) {
  34. return false;
  35. }
  36. return !(this.converter instanceof ConditionalConverter) ||
  37. ((ConditionalConverter) this.converter).matches(sourceType, targetType);
  38. }
  39.  
  40. @Override
  41. @Nullable
  42. public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
  43. if (source == null) {
  44. return convertNullSource(sourceType, targetType);
  45. }
  46. return this.converter.convert(source);
  47. }
  48.  
  49. @Override
  50. public String toString() {
  51. return (this.typeInfo + " : " + this.converter);
  52. }
  53. }
  54.  
  55. private final class ConverterFactoryAdapter implements ConditionalGenericConverter {
  56.  
  57. private final ConverterFactory<Object, Object> converterFactory;
  58.  
  59. private final ConvertiblePair typeInfo;
  60.  
  61. public ConverterFactoryAdapter(ConverterFactory<?, ?> converterFactory, ConvertiblePair typeInfo) {
  62. this.converterFactory = (ConverterFactory<Object, Object>) converterFactory;
  63. this.typeInfo = typeInfo;
  64. }
  65.  
  66. @Override
  67. public Set<ConvertiblePair> getConvertibleTypes() {
  68. return Collections.singleton(this.typeInfo);
  69. }
  70.  
  71. @Override
  72. public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
  73. boolean matches = true;
  74. if (this.converterFactory instanceof ConditionalConverter) {
  75. matches = ((ConditionalConverter) this.converterFactory).matches(sourceType, targetType);
  76. }
  77. if (matches) {
  78. Converter<?, ?> converter = this.converterFactory.getConverter(targetType.getType());
  79. if (converter instanceof ConditionalConverter) {
  80. matches = ((ConditionalConverter) converter).matches(sourceType, targetType);
  81. }
  82. }
  83. return matches;
  84. }
  85.  
  86. @Override
  87. @Nullable
  88. public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
  89. if (source == null) {
  90. return convertNullSource(sourceType, targetType);
  91. }
  92. return this.converterFactory.getConverter(targetType.getObjectType()).convert(source);
  93. }
  94.  
  95. @Override
  96. public String toString() {
  97. return (this.typeInfo + " : " + this.converterFactory);
  98. }
  99. }

(3):转换器存储设计

  1.  
  1. private final Converters converters = new Converters();
  2.  
  3. /**
  4. * Manages all converters registered with the service.
  5. */
  6. private static class Converters {

  7. private final Set<GenericConverter> globalConverters = new LinkedHashSet<>();

  8. private final Map<ConvertiblePair, ConvertersForPair> converters = new LinkedHashMap<>(36);
  9. }

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

  1.  
  1. /**
  2. * General NO-OP converter used when conversion is not required.
  3. */
  4. private static final GenericConverter NO_OP_CONVERTER = new NoOpConverter("NO_OP");

  5. /**
  6. * Used as a cache entry when no converter is available.
  7. * This converter is never returned.
  8. */
  9. private static final GenericConverter NO_MATCH = new NoOpConverter("NO_MATCH");



  10. /**
  11. * Internal converter that performs no operation.
  12. */
  13. private static class NoOpConverter implements GenericConverter {

  14. private final String name;

  15. public NoOpConverter(String name) {
  16. this.name = name;
  17. }

  18. @Override
  19. public Set<ConvertiblePair> getConvertibleTypes() {
  20. return null;
  21. }

  22. @Override
  23. @Nullable
  24. public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
  25. return source;
  26. }

  27. @Override
  28. public String toString() {
  29. return this.name;
  30. }
  31. }

总结

  • 适配器合理设计

  • 缓存合理设计

  • 存储合理设计

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

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

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

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

(3):DefaultConversionService源码学习

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

  1. public class DefaultConversionService extends GenericConversionService {

  2. @Nullable
  3. private static volatile DefaultConversionService sharedInstance;


  4. /**
  5. * Create a new {@code DefaultConversionService} with the set of
  6. * {@linkplain DefaultConversionService#addDefaultConverters(ConverterRegistry) default converters}.
  7. */
  8. public DefaultConversionService() {
  9. addDefaultConverters(this);
  10. }


  11. /**
  12. * Return a shared default {@code ConversionService} instance,
  13. * lazily building it once needed.
  14. * <p><b>NOTE:</b> We highly recommend constructing individual
  15. * {@code ConversionService} instances for customization purposes.
  16. * This accessor is only meant as a fallback for code paths which
  17. * need simple type coercion but cannot access a longer-lived
  18. * {@code ConversionService} instance any other way.
  19. * @return the shared {@code ConversionService} instance (never {@code null})
  20. * @since 4.3.5
  21. */
  22. public static ConversionService getSharedInstance() {
  23. DefaultConversionService cs = sharedInstance;
  24. if (cs == null) {
  25. synchronized (DefaultConversionService.class) {
  26. cs = sharedInstance;
  27. if (cs == null) {
  28. cs = new DefaultConversionService();
  29. sharedInstance = cs;
  30. }
  31. }
  32. }
  33. return cs;
  34. }
  35. }

  36. 总结
  37.  
  38. 单例模式之双重检锁模式正确运用
  39.  
  40. (4):ConversionServiceFactoryBean(类型转换器注册工厂Bean)
  41.  
  42. /**
  43. * A factory providing convenient access to a ConversionService configured with
  44. * converters appropriate for most environments. Set the
  45. * {@link #setConverters "converters"} property to supplement the default converters.
  46. *
  47. * <p>This implementation creates a {@link DefaultConversionService}.
  48. * Subclasses may override {@link #createConversionService()} in order to return
  49. * a {@link GenericConversionService} instance of their choosing.
  50. *
  51. * <p>Like all {@code FactoryBean} implementations, this class is suitable for
  52. * use when configuring a Spring application context using Spring {@code <beans>}
  53. * XML. When configuring the container with
  54. * {@link org.springframework.context.annotation.Configuration @Configuration}
  55. * classes, simply instantiate, configure and return the appropriate
  56. * {@code ConversionService} object from a {@link
  57. * org.springframework.context.annotation.Bean @Bean} method.
  58. * @since 3.0
  59. */
  60. public class ConversionServiceFactoryBean implements FactoryBean<ConversionService>, InitializingBean {

  61. @Nullable
  62. private Set<?> converters;

  63. @Nullable
  64. private GenericConversionService conversionService;


  65. /**
  66. * Configure the set of custom converter objects that should be added:
  67. * implementing {@link org.springframework.core.convert.converter.Converter},
  68. * {@link org.springframework.core.convert.converter.ConverterFactory},
  69. * or {@link org.springframework.core.convert.converter.GenericConverter}.
  70. */
  71. public void setConverters(Set<?> converters) {
  72. this.converters = converters;
  73. }

  74. @Override
  75. public void afterPropertiesSet() {
  76. this.conversionService = createConversionService();
  77. ConversionServiceFactory.registerConverters(this.converters, this.conversionService);
  78. }

  79. /**
  80. * Create the ConversionService instance returned by this factory bean.
  81. * <p>Creates a simple {@link GenericConversionService} instance by default.
  82. * Subclasses may override to customize the ConversionService instance that
  83. * gets created.
  84. */
  85. protected GenericConversionService createConversionService() {
  86. return new DefaultConversionService();
  87. }


  88. // implementing FactoryBean

  89. @Override
  90. @Nullable
  91. public ConversionService getObject() {
  92. return this.conversionService;
  93. }

  94. @Override
  95. public Class<? extends ConversionService> getObjectType() {
  96. return GenericConversionService.class;
  97. }

  98. @Override
  99. public boolean isSingleton() {
  100. return true;
  101. }

  102. }


  103. /**
  104. * A factory for common {@link org.springframework.core.convert.ConversionService}
  105. * configurations.
  106. * @since 3.0
  107. */
  108. public abstract class ConversionServiceFactory {

  109. /**
  110. * Register the given Converter objects with the given target ConverterRegistry.
  111. * @param converters the converter objects: implementing {@link Converter},
  112. * {@link ConverterFactory}, or {@link GenericConverter}
  113. * @param registry the target registry
  114. */
  115. public static void registerConverters(@Nullable Set<?> converters, ConverterRegistry registry) {
  116. if (converters != null) {
  117. for (Object converter : converters) {
  118. if (converter instanceof GenericConverter) {
  119. registry.addConverter((GenericConverter) converter);
  120. }
  121. else if (converter instanceof Converter<?, ?>) {
  122. registry.addConverter((Converter<?, ?>) converter);
  123. }
  124. else if (converter instanceof ConverterFactory<?, ?>) {
  125. registry.addConverterFactory((ConverterFactory<?, ?>) converter);
  126. }
  127. else {
  128. throw new IllegalArgumentException("Each converter object must implement one of the " +
  129. "Converter, ConverterFactory, or GenericConverter interfaces");
  130. }
  131. }
  132. }
  133. }

  134. }

总结

  • 简单工厂模式运用

  • 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类型转换源码探究)的更多相关文章

  1. Spring Type Conversion(Spring类型转换)

    Spring Type Conversion(Spring类型转换) 1:概述: Spring3引入了core.convert包,提供了通用类型转换系统,定义了实现类型转换和运行时执行类型的SPI. ...

  2. Mybatis的初始化和结合Spring Framework后初始化的源码探究

    带着下面的问题进行学习: (1)Mybatis 框架或 Spring Framework 框架对数据层 Mapper 接口做了代理,那是做了 JDK 动态代理还是 CGLIB 代理? (2)Mappe ...

  3. Mybatis一级缓存和结合Spring Framework后失效的源码探究

    1.在下面的案例中,执行两次查询控制台只会输出一次 SQL 查询: mybatis-config.xml <?xml version="1.0" encoding=" ...

  4. Spring Framework自动装配setAutowireMode和Mybatis案例的源码探究

    由前文可得知, Spring Framework的自动装配有两种方式:xml配置和注解配置: 自动装配的类型有: (1)xml配置中的byType根据类型查找(@Autowired注解是默认根据类型查 ...

  5. Spring Environment(二)源码分析

    Spring Environment(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Envi ...

  6. 七、Spring之深入理解AOP源码

    Spring之深入理解AOP源码 ​ 在上一篇博文中,我们对AOP有了初步的了解,那么接下来我们就对AOP的实现原理进行深入的分析. ​ 在之前写的那个AOP示例代码当中有这样一个注解:@Enable ...

  7. Spring框架之spring-web http源码完全解析

    Spring框架之spring-web http源码完全解析 Spring-web是Spring webMVC的基础,由http.remoting.web三部分组成. http:封装了http协议中的 ...

  8. Spring框架之spring-web web源码完全解析

    Spring框架之spring-web web源码完全解析 spring-web是Spring webMVC的基础,由http.remoting.web三部分组成,核心为web模块.http模块封装了 ...

  9. 一文读懂Spring动态配置多数据源---源码详细分析

    Spring动态多数据源源码分析及解读 一.为什么要研究Spring动态多数据源 ​ 期初,最开始的原因是:想将答题服务中发送主观题答题数据给批改中间件这块抽象出来, 但这块主要使用的是mq消息的方式 ...

随机推荐

  1. WPF 高速书写 StylusPlugIn 原理

    原文:WPF 高速书写 StylusPlugIn 原理 本文告诉大家 WPF 的 StylusPlugIn 为什么能做高性能书写,在我的上一篇博客和大家介绍了 WPF 的触摸原理,但是没有详细告诉大家 ...

  2. Spring+SpringMVC+MyBatis+easyUI

    Spring+SpringMVC+MyBatis+easyUI 日常啰嗦 还好在第一篇文章里就列好了接下来的主线及要写的知识点,不然都不知道要写什么东西了,开篇里已经列了基础篇要讲svn和git的知识 ...

  3. oracle的number的浅析

    author:skate time:2011-02-14 oracle的number的浅析 从例如以下几个方面来认识number 1.表示的数值范围   2.占用的存储空间   3.number的性能 ...

  4. LVS实现负载均衡原理及安装配置

    LVS实现负载均衡原理及安装配置 负载均衡集群是 load balance 集群的简写,翻译成中文就是负载均衡集群.常用的负载均衡开源软件有nginx.lvs.haproxy,商业的硬件负载均衡设备F ...

  5. 将git文件挂到cdn上

    网址:http://raw.githack.com/

  6. hdu 3966 树链分割第一3遍

    真的不好意思说话.你写得越多,对风暴各种问题泄露,更离谱,有什么错有.. .但是,仍然有一个.同时经过规范的编写清晰的代码.不能认为是理所当然... 树桩阵列版: #include<cstdio ...

  7. 制作WPF时钟之2

    原文:制作WPF时钟之2 前段时间写了一篇"制作简单的WPF时钟",今天再制作了一个更漂亮的WPF时钟,目前仅完成了设计部分,准备将它制作成一个无边框窗体式的时钟. 效果图:   ...

  8. Python抓取小说

    Python抓取小说 前言 这个脚本命令MAC在抓取小说写,使用Python它有几个码. 代码 # coding=utf-8 import re import urllib2 import chard ...

  9. 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 ...

  10. WPF特效-拼图游戏

    原文:WPF特效-拼图游戏 此文主要描述我实现碎片化的便捷过程. 步骤1:    选取参考图如下(百度图库搜的): 步骤2:    根据效果图或者模型构建贝塞尔曲线,为了方便查看效果,可以设置控制点, ...