Spring 类型转换
Spring 类型转换
Spring 类型转换的实现
- 基于 JavaBeans 接口的类型转换实现
- 基于 java.beans.PropertyEditor 接口扩展
- Spring 3.0+ 通用类型转换实现
使用场景
场景 | 基于 JavaBeans 接口的类型转换实现 | Spring 3.0+ 通用类型转换实现 |
---|---|---|
数据绑定 | YES | YES |
BeanWrapper | YES | YES |
Bean 属性类型转换 | YES | YES |
外部化属性类型转换 | NO | YES |
基于 JavaBeans 接口的类型转换
核心职责
- 将 String 类型的内容转化为目标类型的对象
扩展原理
- Spring 框架将文本内容传递到 PropertyEditor 实现的 setAsText(String) 方法
- PropertyEditor#setAsText(String) 方法实现将 String 类型转化为目标类型的对象
- 将目标类型的对象传入 PropertyEditor#setValue(Object) 方法
- PropertyEditor#setValue(Object) 方法实现需要临时存储传入对象
- Spring 框架将通过 PropertyEditor#getValue() 获取类型转换后的对象
Spring 內建 PropertyEditor 扩展
內建扩展(org.springframework.beans.propertyeditors 包下)
转换场景 | 实现类 |
---|---|
String -> Byte 数组 | org.springframework.beans.propertyeditors.ByteArrayPropertyEditor |
String -> Char | org.springframework.beans.propertyeditors.CharacterEditor |
String -> Char 数组 | org.springframework.beans.propertyeditors.CharArrayPropertyEditor |
String -> Charset | org.springframework.beans.propertyeditors.CharsetEditor |
String -> Class | org.springframework.beans.propertyeditors.ClassEditor |
String -> Currency | org.springframework.beans.propertyeditors.CurrencyEditor |
自定义 PropertyEditor 扩展
扩展模式
- 扩展
java.beans.PropertyEditorSupport
类
实现 org.springframework.beans.PropertyEditorRegistrar
- 实现
registerCustomEditors(org.springframework.beans.PropertyEditorRegistry)
方法 - 将
PropertyEditorRegistrar
实现注册为 Spring Bean
向 org.springframework.beans.PropertyEditorRegistry
注册自定义 PropertyEditor 实现
- 通用类型实现
registerCustomEditor(Class<?>, PropertyEditor)
- Java Bean 属性类型实现:
registerCustomEditor(Class<?>, String, PropertyEditor)
Spring PropertyEditor 的设计缺陷
违反职责单一原则
java.beans.PropertyEditor
接口职责太多,除了类型转换,还包括 Java Beans 事件和 Java GUI 交
互
java.beans.PropertyEditor
实现类型局限
- 来源类型只能为
java.lang.String
类型
java.beans.PropertyEditor
实现缺少类型安全
- 除了实现类命名可以表达语义,实现类无法感知目标转换类型
Spring 3 通用类型转换接口
类型转换接口 - org.springframework.core.convert.converter.Converter<S,T>
- 泛型参数 S:来源类型,参数 T:目标类型
- 核心方法:T convert(S)
通用类型转换接口 - org.springframework.core.convert.converter.GenericConverter
- 核心方法:convert(Object,TypeDescriptor,TypeDescriptor)
- 配对类型:org.springframework.core.convert.converter.GenericConverter.ConvertiblePair
- 类型描述:org.springframework.core.convert.TypeDescriptor
Spring 內建类型转换器
內建扩展
转换场景 | 实现类所在包名(package) |
---|---|
日期/时间相关 | org.springframework.format.datetime |
Java 8 日期/时间相关 | org.springframework.format.datetime.standard |
通用实现 | org.springframework.core.convert.support |
Converter 接口的局限性
局限一:缺少 Source Type 和 Target Type 前置判断
- 应对:增加 org.springframework.core.convert.converter.ConditionalConverter 实现
局限二:仅能转换单一的 Source Type 和 Target Type
- 应对:使用 org.springframework.core.convert.converter.GenericConverter 代替
GenericConverter 接口
org.springframework.core.convert.converter.GenericConverter
核心要素 | 说明 |
---|---|
使用场景 | 用于“复合”类型转换场景,比如 Collection、Map、数组等 |
转换范围 | Set<ConvertiblePair> getConvertibleTypes() |
配对类型 | org.springframework.core.convert.converter.GenericConverter.ConvertiblePair |
转换方法 | convert(Object,TypeDescriptor,TypeDescriptor) |
类型描述 | org.springframework.core.convert.TypeDescriptor |
优化 GenericConverter 接口
GenericConverter 局限性
- 缺少 Source Type 和 Target Type 前置判断
- 单一类型转换实现复杂
GenericConverter 优化接口 - ConditionalGenericConverter
- 复合类型转换:
org.springframework.core.convert.converter.GenericConverter
- 类型条件判断:
org.springframework.core.convert.converter.ConditionalConverter
扩展 Spring 类型转换器
实现转换器接口
org.springframework.core.convert.converter.Converter
org.springframework.core.convert.converter.ConverterFactory
org.springframework.core.convert.converter.GenericConverter
注册转换器实现
- 通过
ConversionServiceFactoryBean
Spring Bean - 通过
org.springframework.core.convert.ConversionService API
统一类型转换服务
org.springframework.core.convert.ConversionService
实现类型 | 说明 |
---|---|
GenericConversionService | 通用 ConversionService 模板实现,不内置转化器实现 |
DefaultConversionService | 基础 ConversionService 实现,内置常用转化器实现 |
FormattingConversionService | 通用 Formatter + GenericConversionService 实现,不内置转化器和 Formatter 实现 |
DefaultFormattingConversionService | DefaultConversionService + 格式化 实现(如:JSR-354 Money & Currency, JSR-310 Date-Time) |
ConversionService 作为依赖
类型转换器底层接口 - org.springframework.beans.TypeConverter
- 起始版本:Spring 2.0
- 核心方法 - convertIfNecessary 重载方法
- 抽象实现 -
org.springframework.beans.TypeConverterSupport
- 简单实现 -
org.springframework.beans.SimpleTypeConverter
类型转换器底层抽象实现 - org.springframework.beans.TypeConverterSupport
- 实现接口 -
org.springframework.beans.TypeConverter
- 扩展实现 -
org.springframework.beans.PropertyEditorRegistrySupport
- 委派实现 -
org.springframework.beans.TypeConverterDelegate
类型转换器底层委派实现 - org.springframework.beans.TypeConverterDelegate
- 构造来源 -
org.springframework.beans.AbstractNestablePropertyAccessor
实现org.springframework.beans.BeanWrapperImpl
- 依赖 -
java.beans.PropertyEditor
实现- 默认內建实现 -
PropertyEditorRegistrySupport#registerDefaultEditors
- 默认內建实现 -
- 可选依赖 -
org.springframework.core.convert.ConversionService
实现
问题
Spring 类型转换实现有哪些?
- 基于 JavaBeans PropertyEditor 接口实现
- Spring 3.0+ 通用类型转换实现
Spring 类型转换器接口有哪些?
- 类型转换接口 -
org.springframework.core.convert.converter.Converter
- 通用类型转换接口 -
org.springframework.core.convert.converter.GenericConverter
- 类型条件接口 -
org.springframework.core.convert.converter.ConditionalConverter
- 综合类型转换接口 -
org.springframework.core.convert.converter.ConditionalGenericConverter