3.4. spring类型转换
Spring 3 引入了一个core.convert
提供通用类型转换系统的包。系统定义了一个 SPI 来实现类型转换逻辑和一个 API 来在运行时执行类型转换。在 Spring 容器中,您可以使用此系统作为实现的替代PropertyEditor
方案,将外部化的 bean 属性值字符串转换为所需的属性类型。您还可以在应用程序中需要类型转换的任何地方使用公共 API。
3.4.1. 转换器 SPI
实现类型转换逻辑的 SPI 很简单,而且是强类型的,如下面的接口定义所示:
要创建您自己的转换器,请实现 Converter
接口并将 S
参数化为要转换的类型,将T
参数化为要转换的目标类型。如果需要将 S
的集合或数组转换为T
的数组或集合,您还可以透明地应用此类转换器,前提是委托数组或集合转换器也已注册(默认情况下 DefaultConversionService
会注册)。
对于每次调用convert(S)
,源参数保证不为空。如果转换失败, Converter
可能会抛出任何未经检查的异常。具体来说,它应该抛出一个 IllegalArgumentException
报告无效的源值。注意确保您的Converter
实现是线程安全的。
为方便起见,软件包core.convert.support
中提供了几个转换器实现。这些包括从字符串到数字和其他常见类型的转换器。下面的清单显示了这个StringToInteger
类,它是一个典型的Converter
实现:
3.4.2. 使用ConverterFactory
当您需要集中整个类层次结构的转换逻辑时(例如,从转换String
为Enum
对象时),您可以实现 ConverterFactory
,如以下示例所示:
将 S 参数化为要转换的类型,将 R 参数化为定义可以转换为的类*范围的基本类型。*然后实现getConverter(Class<T>)
,其中 T 是 R 的子类。
考虑StringToEnumConverterFactory
作为一个例子:
3.4.3. 使用GenericConverter
当您需要复杂的Converter
实现时,请考虑使用 GenericConverter
接口。与Converter
相比,GenericConverter
具有更灵活但类型更弱的签名,支持在多个源类型和目标类型之间进行转换。此外,GenericConverter
提供了可用的源和目标字段上下文,您可以在实现转换逻辑时使用它们。这样的上下文允许类型转换由字段注解或字段签名上声明的通用信息驱动。以下清单显示了 GenericConverter
的接口定义:
要实现 GenericConverter
,getConvertibleTypes()
需要返回支持的源→目标类型对。然后实现convert(Object, TypeDescriptor, TypeDescriptor)
以包含您的转换逻辑。源TypeDescriptor
提供对保存正在转换的值的源字段的访问。目标TypeDescriptor
提供对要设置转换值的目标字段的访问。
GenericConverter
很好的例子是在 Java 数组和集合之间转换的转换器。ArrayToCollectionConverter
内省了声明目标集合类型的字段来解析集合的元素类型。这使得源数组中的每个元素在集合被设置到目标字段之前被转换为集合元素类型。
因为GenericConverter
是比较复杂的 SPI 接口,所以应该只在需要的时候使用。支持Converter
或ConverterFactory
满足基本类型转换需求。
使用ConditionalGenericConverter
有时,您希望转换器仅在特定条件成立时运行。例如,您可能希望仅当目标字段上存在特定注解时才运行 Converter
,或者仅当目标类上定义了特定方法(例如静态valueOf
方法)时您可能希望运行 Converter
。 ConditionalGenericConverter
是 GenericConverter
和ConditionalConverter
接口的联合,可让您定义此类自定义匹配条件:
ConditionalGenericConverter
很好的例子是IdToEntityConverter
在持久实体标识符和实体引用之间进行转换。IdToEntityConverter
只有当目标实体类型声明了静态查找器方法(例如, findAccount(Long)
)时,这样的才可能匹配。您可以在matches(TypeDescriptor, TypeDescriptor)
的实现中执行此类查找器方法检查。
3.4.4. ConversionService
API
ConversionService
定义了一个统一的 API,用于在运行时执行类型转换逻辑。转换器通常在以下外观接口后面运行:
大多数ConversionService
实现还实现了ConverterRegistry
,它提供了一个用于注册转换器的 SPI。在内部,ConversionService
实现委托其注册的转换器执行类型转换逻辑。
core.convert.support
包中提供了强大的 ConversionService
实现。GenericConversionService
是适合在大多数环境中使用的通用实现。 ConversionServiceFactory
提供了一个方便的工厂来创建常见的 ConversionService
配置。
3.4.5. 配置ConversionService
ConversionService
是一个无状态对象,旨在在应用程序启动时实例化,然后在多个线程之间共享。在 Spring 应用程序中,您通常为每个 Spring 容器(或ApplicationContext
)配置一个ConversionService
实例。每当框架需要执行类型转换时,Spring 就会选择并使用ConversionService
。您还可以将ConversionService
注入任何 bean 并直接调用。
如果没有 Spring 向注册ConversionService
,则使用默认的PropertyEditor
。
要使用 Spring 注册默认值,添加以下 id
为 conversionService
的 bean
定义:
ConversionService
默认值可以在字符串、数字、枚举、集合、映射和其他常见类型之间进行转换。要使用您自己的自定义转换器补充或覆盖默认转换器,请设置converters
属性。属性值可以实现任何Converter
、ConverterFactory
或GenericConverter
接口。
在 Spring MVC 应用程序中使用 ConversionService
也很常见。请参阅 Spring MVC 章节中的转换和格式化。
在某些情况下,您可能希望在转换期间应用格式。有关使用参考 The FormatterRegistry
SPI for details on using FormattingConversionServiceFactoryBean
.
3.4.6. 以编程方式使用ConversionService
要以编程方式使用ConversionService
实例,您可以像对任何其他 bean 一样注入对它的引用。以下示例显示了如何执行此操作:
对于大多数用例,您可以使用指定 targetType
的convert
方法,但它不适用于更复杂的类型,例如参数化元素的集合。例如,如果您想以编程方式将Integer类型的List转换为String类型的list,则需要提供源类型和目标类型的正式定义。
幸运的是,TypeDescriptor
提供了各种选项来使操作变得简单,如以下示例所示:
请注意,DefaultConversionService
的自动注册适用于大多数环境的转换器。这包括集合转换器、标量转换器和基本Object
到String
转换器。您可以使用DefaultConversionService
类上的静态addDefaultConverters
方法向ConverterRegistry
注册相同的转换器。
值类型的转换器可用于数组和集合,因此无需创建特定的转换器来从 Collection <S>
转换为 Collection <T>
,假设标准集合处理是合适的。
最后更新于