Spring 扩展之深入分析 Bean 的类型转换体系

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们知道不管 bean 对象里面的属性时什么类型,他们都是通过 XML 、Properties 或者其他方式来配置这些属性对象类型的。在 Spring 容器加载过程中,这些属性都是以 String 类型加载进容器的,但是最终都需要将这些 String 类型的属性转换 Bean 对象属性所对应真正的类型,要想完成这种由字符串到具体对象的转换,就需要这种转换规则相关的信息,而这些信息以及转换过程由 Spring 类型转换体系来完成。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们依然以 xml 为例,在 Spring 容器加载阶段,容器将 xml 文件中定义的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"","attrs":{}}],"attrs":{}},{"type":"text","text":" 解析为 BeanDefinition,BeanDefinition 中存储着我们定义一个 bean 需要的所有信息,包括属性,这些属性是以 String 类型的存储的。当用户触发 Bean 实例化阶段时,Spring 容器会将这些属性转换为这些属性真正对应的类型。我们知道在 bean 实例化阶段,属性的注入是在实例化 bean 阶段的属性注入阶段,即 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"populateBean()","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法。在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"populateBean()","attrs":{}}],"attrs":{}},{"type":"text","text":" 中会将 BeanDefinition 中定义的属性值翻译为 PropertyValue 然后调用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"applyPropertyValues()","attrs":{}}],"attrs":{}},{"type":"text","text":" 进行属性应用。其中 PropertyValue 用于保存单个 bean 属性的信息和值的对象。在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"applyPropertyValues()","attrs":{}}],"attrs":{}},{"type":"text","text":" 中会调用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"convertForProperty()","attrs":{}}],"attrs":{}},{"type":"text","text":" 进行属性转换,如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private Object convertForProperty(\n @Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {\n\n if (converter instanceof BeanWrapperImpl) {\n return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);\n }\n else {\n PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);\n MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);\n return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"若 TypeConverter 为 BeanWrapperImpl 类型,则使用 BeanWrapperImpl 来进行类型转换,这里主要是因为 BeanWrapperImpl 实现了 PropertyEditorRegistry 接口。否则则调用 TypeConverter 的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"convertIfNecessary()","attrs":{}}],"attrs":{}},{"type":"text","text":" 进行类型转换。TypeConverter 是定义类型转换方法的接口,通常情况下与 PropertyEditorRegistry 配合使用实现类型转换。关于 BeanWrapperImpl 小编后续专门出文分析它。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"convertIfNecessary()","attrs":{}}],"attrs":{}},{"type":"text","text":" 的实现者有两个:DataBinder 和 TypeConverterSupport ,其中 DataBinder 主要用于参数绑定(熟悉 Spring MVC 的都应该知道这个类),TypeConverterSupport 则是 TypeConverter 的基本实现,使用的是 package-private 策略。 所以这里我们只需要关注 TypeConverterSupport 的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"convertIfNecessary()","attrs":{}}],"attrs":{}},{"type":"text","text":",如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public T convertIfNecessary(@Nullable Object value, @Nullable Class requiredType, @Nullable MethodParameter methodParam)\n throws TypeMismatchException {\n\n return doConvert(value, requiredType, methodParam, null);\n}\n\nprivate T doConvert(@Nullable Object value,@Nullable Class requiredType,\n @Nullable MethodParameter methodParam, @Nullable Field field) throws TypeMismatchException {\n\n Assert.state(this.typeConverterDelegate != null, \"No TypeConverterDelegate\");\n try {\n if (field != null) {\n return this.typeConverterDelegate.convertIfNecessary(value, requiredType, field);\n }\n else {\n return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);\n }\n }\n catch (ConverterNotFoundException | IllegalStateException ex) {\n throw new ConversionNotSupportedException(value, requiredType, ex);\n }\n catch (ConversionException | IllegalArgumentException ex) {\n throw new TypeMismatchException(value, requiredType, ex);\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们一直往下跟会跟踪到 TypeConverterDelegate 的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"convertIfNecessary()","attrs":{}}],"attrs":{}},{"type":"text","text":" ,会发现如下代码段:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/66/66353a9c50e322e965648beda62e74cf.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果没有自定义的编辑器则使用 ConversionService 。ConversionService 是 Spring 自 3 后推出来用来替代 PropertyEditor 转换模式的转换体系,接口定义如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public interface ConversionService {\n\n boolean canConvert(@Nullable Class> sourceType, Class> targetType);\n\n boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);\n\n @Nullable\n T convert(@Nullable Object source, Class targetType);\n\n @Nullable\n Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其 UML 类图如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/5d/5dae2df55357fdf3f3e5a3c7470e5c6b.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"ConfigurableConversionService","attrs":{}},{"type":"text","text":":ConversionService 的配置接口,继承 ConversionService 和 ConverterRegistry 两个接口,用于合并他们两者的操作,以便于通过 add 和 remove 的方式添加和删除转换器。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"GenericConversionService","attrs":{}},{"type":"text","text":":ConversionService 接口的基础实现,适用于大部分条件下的转换工作,通过 ConfigurableConversionService 接口间接地将 ConverterRegistry 实现为注册 API 。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"DefaultConversionService","attrs":{}},{"type":"text","text":":ConversionService 接口的默认实现,适用于大部分条件下的转换工作。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"回归到 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"convertIfNecessary()","attrs":{}}],"attrs":{}},{"type":"text","text":",在该方法中如果没有自定义的属性编辑器则调用 ConversionService 接口的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"convert()","attrs":{}}],"attrs":{}},{"type":"text","text":",方法定义如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"source:要转换的源对象,可以为 null","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"sourceType:source 的类型的上下文,如果 source 为 null,则可以为 null","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"targetType:source 要转换的类型的上下文。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"convert()","attrs":{}}],"attrs":{}},{"type":"text","text":" 将给定的源对象 source 转换为指定的 targetType。TypeDescriptors 提供有关发生转换的源位置和目标位置的附加上下文,通常是对象字段或属性位置。方法由子类 GenericConversionService 实现:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {\n // 删掉 if ,其实就是上面的 null 判断\n GenericConverter converter = getConverter(sourceType, targetType);\n if (converter != null) {\n Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);\n return handleResult(sourceType, targetType, result);\n }\n return handleConverterNotFound(source, sourceType, targetType);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先根据 sourceType 和 targetType 调用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"getConverter()","attrs":{}}],"attrs":{}},{"type":"text","text":" 获取 GenericConverter 对象 converter ,如果 converter 为 null,则调用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"handleConverterNotFound()","attrs":{}}],"attrs":{}},{"type":"text","text":",否则调用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"handleResult()","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法。","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"getConverter()","attrs":{}}],"attrs":{}},{"type":"text","text":" 如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {\n ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);\n GenericConverter converter = this.converterCache.get(key);\n if (converter != null) {\n return (converter != NO_MATCH ? converter : null);\n }\n\n converter = this.converters.find(sourceType, targetType);\n if (converter == null) {\n converter = getDefaultConverter(sourceType, targetType);\n }\n\n if (converter != null) {\n this.converterCache.put(key, converter);\n return converter;\n }\n\n this.converterCache.put(key, NO_MATCH);\n return null;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这段代码意图非常明确,从 converterCache 缓存中获取,如果存在返回,否则从 converters 中获取,然后加入到 converterCache 缓存中。converterCache 和 converters 是 GenericConversionService 维护的两个很重要的对象,其中 converterCache 用于存储 GenericConverter ,converters 对象为 GenericConversionService 的内部类。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private final Converters converters = new Converters();\nprivate final Map converterCache = new ConcurrentReferenceHashMap<>(64);\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Converters 用于管理所有注册的转换器,其内部维护一个 Set 和 Map 的数据结构用于管理转换器,如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private final Set globalConverters = new LinkedHashSet<>();\n\nprivate final Map converters = new LinkedHashMap<>(36);\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"同时提供了相应的方法(如 add、remove)操作这两个集合。在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"getConverter()","attrs":{}}],"attrs":{}},{"type":"text","text":" 中如果缓存 converterCache 中 不存在,则调用 Converters 对象的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"find()","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法获取相应的 GenericConverter,如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) {\n // Search the full type hierarchy\n List> sourceCandidates = getClassHierarchy(sourceType.getType());\n List> targetCandidates = getClassHierarchy(targetType.getType());\n for (Class> sourceCandidate : sourceCandidates) {\n for (Class> targetCandidate : targetCandidates) {\n ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate);\n GenericConverter converter = getRegisteredConverter(sourceType, targetType, convertiblePair);\n if (converter != null) {\n return converter;\n }\n }\n }\n return null;\n}\n\nprivate GenericConverter getRegisteredConverter(TypeDescriptor sourceType,\n TypeDescriptor targetType, ConvertiblePair convertiblePair) {\n\n // Check specifically registered converters\n ConvertersForPair convertersForPair = this.converters.get(convertiblePair);\n if (convertersForPair != null) {\n GenericConverter converter = convertersForPair.getConverter(sourceType, targetType);\n if (converter != null) {\n return converter;\n }\n }\n // Check ConditionalConverters for a dynamic match\n for (GenericConverter globalConverter : this.globalConverters) {\n if (((ConditionalConverter) globalConverter).matches(sourceType, targetType)) {\n return globalConverter;\n }\n }\n return null;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"find()","attrs":{}}],"attrs":{}},{"type":"text","text":" 中会根据 sourceType 和 targetType 去查询 Converters 中维护的 Map 中是否包括支持的注册类型,如果存在返回 GenericConverter ,如果没有存在返回 null。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当得到 GenericConverter 后,则调用其 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"convert()","attrs":{}}],"attrs":{}},{"type":"text","text":" 进行类型转换。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType);\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"到这里我们就可以得到 bean 属性定义的真正类型了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"GenericConverter 接口","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"GenericConverter 是一个转换接口,一个用于在两种或更多种类型之间转换的通用型转换器接口。它是 Converter SPI 体系中最灵活的,也是最复杂的接口,灵活性在于 GenericConverter 可以支持在多个源/目标类型对之间进行转换,同时也可以在类型转换过程中访问源/目标字段上下文。由于该接口足够复杂,所有当更简单的 Converter 或 ConverterFactory 接口足够使用时,通常不应使用此接口。其定义如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public interface GenericConverter {\n\n @Nullable\n Set getConvertibleTypes();\n\n @Nullable\n Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"GenericConverter 的子类有这么多(看类名就知道是干嘛的了):","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ae/ae851c788e7011fd6e325056cab2f797.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们看一个子类的实现 StringToArrayConverter,该子类将逗号分隔的 String 转换为 Array。如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n if (source == null) {\n return null;\n }\n String string = (String) source;\n String[] fields = StringUtils.commaDelimitedListToStringArray(string);\n TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();\n Assert.state(targetElementType != null, \"No target element type\");\n Object target = Array.newInstance(targetElementType.getType(), fields.length);\n for (int i = 0; i < fields.length; i++) {\n String sourceElement = fields[i];\n Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetElementType);\n Array.set(target, i, targetElement);\n }\n return target;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在类型转换体系中,Spring 提供了非常多的类型转换器,除了上面的 GenericConverter,还有 Converter、ConditionalConverter、ConverterFactory。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Converter","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Converter 是一个将 S 类型的源对象转换为 T 类型的目标对象的转换器。该接口是线程安全的,所以可以共享。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public interface Converter {\n @Nullable\n T convert(S source);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"子类如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/78/7846fde6784243ff50c21366a438dab6.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"ConditionalConverter","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ConditionalConverter 接口用于表示有条件的类型转换,通过转入的sourceType 与 targetType 判断转换能否匹配,只有可匹配的转换才会调用convert 方法进行转换,如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public interface ConditionalConverter {\n boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ConditionalConverter 的子类如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8a/8a7276c5d8bcdd7a724e69147655a710.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"ConverterFactory","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一个用于“远程”转换的转换工厂,可以将对象从 S 转换为 R 的子类型。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public interface ConverterFactory {\n Converter getConverter(Class targetType);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"子类如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/63/63de40b54f1bc3a032275065d43916a1.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"四种不同的转换器承载着不同的转换过程:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Converter:用于 1:1 的 source -> target 类型转换","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ConverterFactory:用于 1:N 的 source -> target 类型转换","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"GenericConverter用于 N:N 的 source -> target 类型转换","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ConditionalConverter:有条件的 source -> target 类型转换","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"GenericConversionService","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"转换器介绍完了,我们再次回归到 ConversionService 接口中去,该接口定义了两类方法 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"canConvert()","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"convert()","attrs":{}}],"attrs":{}},{"type":"text","text":",其中 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"canConvert()","attrs":{}}],"attrs":{}},{"type":"text","text":" 用于判 sourceType 能否转成 targetType ,而 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"convert()","attrs":{}}],"attrs":{}},{"type":"text","text":" 用于将 source 转成转入的 TargetType 类型实例。这两类方法都是在 GenericConversionService 中实现。类 GenericConversionService 实现 ConfigurableConversionService 接口,而 ConfigurableConversionService 接口继承 ConversionService 和 ConverterRegistry。ConverterRegistry 提供了类型转换器的管理功能,他提供了四个 add 和 一个 remove 方法,支持注册/删除相应的类型转换器。GenericConversionService 作为一个基础实现类,它即支持了不同类型之间的转换,也对各类型转换器进行管理,主要是通过一个 Map 类型的 converterCache 和一个内部类 Converters。在上面已经分析了 GenericConversionService 执行类型转换的过程 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"cover()","attrs":{}}],"attrs":{}},{"type":"text","text":",下面我们就一个 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"addConverter()","attrs":{}}],"attrs":{}},{"type":"text","text":" 来看看它是如何完成转换器的注入工作的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public void addConverter(Converter, ?> converter) {\n ResolvableType[] typeInfo = getRequiredTypeInfo(converter.getClass(), Converter.class);\n if (typeInfo == null && converter instanceof DecoratingProxy) {\n typeInfo = getRequiredTypeInfo(((DecoratingProxy) converter).getDecoratedClass(), Converter.class);\n }\n if (typeInfo == null) {\n throw new IllegalArgumentException(\"Unable to determine source type and target type for your \" +\n \"Converter [\" + converter.getClass().getName() + \"]; does the class parameterize those types?\");\n }\n addConverter(new ConverterAdapter(converter, typeInfo[0], typeInfo[1]));\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先根据 converter 获取 ResolvableType,然后将其与 converter 封装成一个 ConverterAdapter 实例,最后调用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"addConverter()","attrs":{}}],"attrs":{}},{"type":"text","text":"。ResolvableType 用于封装 Java 的类型。ConverterAdapter 则是 Converter 的一个适配器, 它实现了 GenericConverter 和 ConditionalConverter 两个类型转换器。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"addConverter()","attrs":{}}],"attrs":{}},{"type":"text","text":" 如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public void addConverter(GenericConverter converter) {\n this.converters.add(converter);\n invalidateCache();\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"直接调用内部类 Converters 的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"add()","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法,如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public void add(GenericConverter converter) {\n Set convertibleTypes = converter.getConvertibleTypes();\n if (convertibleTypes == null) {\n Assert.state(converter instanceof ConditionalConverter,\n \"Only conditional converters may return null convertible types\");\n this.globalConverters.add(converter);\n }\n else {\n for (ConvertiblePair convertiblePair : convertibleTypes) {\n ConvertersForPair convertersForPair = getMatchableConverters(convertiblePair);\n convertersForPair.add(converter);\n }\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先调用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"getConvertibleTypes()","attrs":{}}],"attrs":{}},{"type":"text","text":" 获取 ConvertiblePair 集合,如果为空,则加入到 globalConverters 集合中,否则通过迭代的方式依次添加。ConvertiblePair 为 source-to-targer 的持有者,它持有 source 和 target 的 class 类型,如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"final class ConvertiblePair {\n private final Class> sourceType;\n private final Class> targetType;\n\n // 其他代码 \n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在迭代过程中会根据 ConvertiblePair 获取相应的 ConvertersForPair ,然后 converter 转换器加入其中,ConvertiblePair 用于管理使用特定GenericConverter.ConvertiblePair 注册的转换器。如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private static class ConvertersForPair {\n\n private final LinkedList converters = new LinkedList<>();\n\n public void add(GenericConverter converter) {\n this.converters.addFirst(converter);\n }\n\n @Nullable\n public GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {\n for (GenericConverter converter : this.converters) {\n if (!(converter instanceof ConditionalGenericConverter) ||\n ((ConditionalGenericConverter) converter).matches(sourceType, targetType)) {\n return converter;\n }\n }\n return null;\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其实内部就是维护一个 LinkedList 集合。他内部有两个方法:","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"add()","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"getConverter()","attrs":{}}],"attrs":{}},{"type":"text","text":",实现较为简单,这里就不多介绍了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"DefaultConversionService","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DefaultConversionService 是 ConversionService 的默认实现,它继承 GenericConversionService,GenericConversionService 主要用于转换器的注册和调用,DefaultConversionService 则是为 ConversionService 体系提供一些默认的转换器。在 DefaultConversionService 构造方法中就会添加默认的 Converter ,如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public DefaultConversionService() {\n addDefaultConverters(this);\n}\n\n public static void addDefaultConverters(ConverterRegistry converterRegistry) {\n addScalarConverters(converterRegistry);\n addCollectionConverters(converterRegistry);\n\n converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry));\n if (jsr310Available) {\n Jsr310ConverterRegistrar.registerJsr310Converters(converterRegistry);\n }\n\n converterRegistry.addConverter(new ObjectToObjectConverter());\n converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry));\n converterRegistry.addConverter(new FallbackObjectToStringConverter());\n if (javaUtilOptionalClassAvailable) {\n converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry));\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当然它还提供了一些其他的方法如 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"addCollectionConverters()","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"addScalarConverters()","attrs":{}}],"attrs":{}},{"type":"text","text":" 用于注册其他类型的转换器。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"至此,从 bean 属性的转换,到 Spring ConversionService 体系的转换器 Converter 以及转换器的管理都介绍完毕了,下篇我们将分析如何利用 ConversionService 实现自定义类型转换器。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章