【小家Spring】聊聊Spring中的数据转换:Converter、ConversionService、TypeConverter、PropertyEditor(下)

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介: 【小家Spring】聊聊Spring中的数据转换:Converter、ConversionService、TypeConverter、PropertyEditor(下)

应用的场景描述:


在基于xml的配置中,我们往往通过字面值为Bean各种类型的属性提供设置值:不管是double类型还是int类型,在配置文件中都对应字符串类型的字面值。

BeanWrapper填充Bean属性时如何将这个字面值转换为对应的double或int等内部类型呢?我们可以隐约地感觉到一定有一个转换器在其中起作用,这个转换器就是属性编辑器。


Spring MVC框架使用多种PropertyEditors分析HTTP请求的各种参数


有的小伙伴可能会问:既然有了PropertyEditor,那为何还需要有Converter呢?其实是因为Java原生的PropertyEditor存在以下两点不足:


  1. 只能用于字符串和Java对象的转换,不适用于任意两个Java类型之间的转换;
  2. 对源对象及目标对象所在的上下文信息(如注解、所在宿主类的结构等)不敏感,在类型转换时不能利用这些上下文信息实施高级转换逻辑。

鉴于此,Spring 3.0在核心模型中添加了一个通用的类型转换模块,类型转换模块位于org.springframework.core.convert包中。Spring希望用这个类型转换体系替换Java标准的PropertyEditor。但由于历史原因,Spring将同时支持两者。在Bean配置、Spring MVC处理方法入参绑定中使用它们。


Spring提供了PropertyEditorRegistry来注册自定义的Editor~ 提供了PropertyEditorRegistrar这个注册官来registerCustomEditors。它的实现类只有ResourceEditorRegistrar使用ResourceLoader来加载资源~默认注册了:Resource、InputStream、InputSource、File、Reader等等和资源先关的属性编辑器。



public interface PropertyEditorRegistry {
  void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor);
  // propertyPath可以是name,可以是person.name这种复合的~~~~
  void registerCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor);
  // 查找一个PropertyEditor 
  @Nullable
  PropertyEditor findCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath);
}

Converter or PropertyEditor?


Spring有两种自动类型转换器,一种是Converter,一种是PropertyEditor。


Converter是类型转换成类型,Editor:从string类型转换为其他类型。

从某种程度上,Converter包含Editor。如果出现需要从string转换到其他类型。首选Editor。


org.springframework.beans.TypeConverter

TypeConverter在org.springframework.expression包中还有一个,注意区分。

// @since 2.0
// 定义类型转换方法的接口。通常(但不一定)与PropertyEditorRegistry接口一起实现
// 通常接口TypeConverter的实现是基于非线程安全的PropertyEditors类,因此也不是线程安全的
public interface TypeConverter {
  // 将参数中的value转换成requiredType类型
  // 从String到任何类型的转换通常使用PropertyEditor类的setAsText方法或ConversionService中的Spring Converter
  @Nullable
  <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType) throws TypeMismatchException;
  // 意义同上,增加了作为转换目标的方法参数,主要用于分析泛型类型,可能是null
  @Nullable
  <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable MethodParameter methodParam) throws TypeMismatchException;
  // 意义同上,增加了转换目标的反射field
  @Nullable
  <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable Field field) throws TypeMismatchException;
  // @since 5.1.4
  @Nullable
  default <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
      @Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {
    throw new UnsupportedOperationException("TypeDescriptor resolution not supported");
  }
}


继承树如下:

image.png


TypeConverterSupport

TypeConverter的基本实现类,同时也是BeanWrapperImpl类的依赖类。


public abstract class TypeConverterSupport extends PropertyEditorRegistrySupport implements TypeConverter {
  @Nullable
  TypeConverterDelegate typeConverterDelegate;
  ... //它所有的convertIfNecessary工作都是委托给了TypeConverterDelegate
}


TypeConverterDelegate

类型转换的委托类,所有类型转换的工作都由该类完成,即将属性转换为其他类型的Spring内部使用方法(内部实现: 先使用PropertyEditor转换器器转换,如果没找到对应的转换器器,会⽤ConversionService来进⾏行行对象转换。)


// @since 2.0
class TypeConverterDelegate {
  // PropertyEditorRegistrySupport#findCustomEditor和getConversionService
  // 就是处理这么一个基本逻辑的~~~~
    private final PropertyEditorRegistrySupport propertyEditorRegistry;
    private final Object targetObject;
    // ......
}


所以从此处就可以看到,PropertyEditor和ConversionService的差别和联系。


SimpleTypeConverter


不在特定目标对象上运行的TypeConverter接口的简单实现。这是使用完整的BeanWrapperImpl实例来实现任意类型转换需求的替代方法,同时使用相同的转换算法(包括委托给PropertyEditor和ConversionService)。

public class SimpleTypeConverter extends TypeConverterSupport {
  public SimpleTypeConverter() {
    this.typeConverterDelegate = new TypeConverterDelegate(this);
    registerDefaultEditors();
  }
}


SimpleTypeConverter经常会被作为默认实现。


PropertyEditor用于字符串到其它对象的转换,由于其局限性,spring提供了converter接口,由ConversionService来调用对外提供服务,而TypeConverter综合了上述两种转换方式,交由TypeConverterDelegate来进行转换。


TypeConverterDelegater先使用PropertyEditor转换器器转换,如果没找到对应的转换器器,会⽤ConversionService来进⾏行行对象转换


总结


1.Spring使用ConversionService来convert各种类型.默认提供的是DefaultConversionService.同时它实现了ConverterRegistry接口,所以也可以添加你自定义的converter.

2.Spring提供了3种converter接口,分别是Converter,ConverterFactory和GenericConverter.一般用于1:1, 1:N, N:N的source->target类型转化.

3.在DefaultConversionService内部3种converter都会转化成GenericConverter放到静态内部类Converters中.

4.接口GenericConverter的内部类ConvertiblePair是source的class与target的Class的封装。GenericConversionService的静态内部类ConvertersForPair是多个converter对应的LinkedList的封装。。。GenericConversionService的静态内部类Converters中含有1个Map<ConvertiblePair, ConvertersForPair>用来储存所有converter.


1个GenericConverter可以对应N个ConvertiblePair,1个ConvertiblePair对应的ConvertersForPair中也可以有N个GenericConverter.

Convertible:可转换的

Spring为何要使用ConversionService替代PropertyEditor

此处总结三个原因,供给大家参考:


  1. ConversionService功能更强大,支持的类型转换范围更广。1. 相比PropertyEditor只提供String<->Object的转换,ConversionService能够提供任意Object<->Object的转换。
  2. ConverterFactory支持一整个class hierarchy的转换(也就是多态),PropertyEditor则不行
  3. Java Bean这个规范最初是和Java GUI(Swing)一起诞生的,PropertyEditor接口里有大量和GUI相关的方法,显然已经过时了。1. Java Bean和POJO不是一个概念,Java Bean不仅有getter、setter,还有一系列和Java GUI配套的东西。

相关文章
|
9月前
|
人工智能 运维 Java
Spring AI Alibaba Admin 开源!以数据为中心的 Agent 开发平台
Spring AI Alibaba Admin 正式发布!一站式实现 Prompt 管理、动态热更新、评测集构建、自动化评估与全链路可观测,助力企业高效构建可信赖的 AI Agent 应用。开源共建,现已上线!
8179 122
|
9月前
|
NoSQL Java 数据库连接
《深入理解Spring》Spring Data——数据访问的统一抽象与极致简化
Spring Data通过Repository抽象和方法名派生查询,简化数据访问层开发,告别冗余CRUD代码。支持JPA、MongoDB、Redis等多种存储,统一编程模型,提升开发效率与架构灵活性,是Java开发者必备利器。(238字)
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——封装统一返回的数据结构
本文介绍了在Spring Boot中封装统一返回的数据结构的方法。通过定义一个泛型类`JsonResult&lt;T&gt;`,包含数据、状态码和提示信息三个属性,满足不同场景下的JSON返回需求。例如,无数据返回时可设置默认状态码&quot;0&quot;和消息&quot;操作成功!&quot;,有数据返回时也可自定义状态码和消息。同时,文章展示了如何在Controller中使用该结构,通过具体示例(如用户信息、列表和Map)说明其灵活性与便捷性。最后总结了Spring Boot中JSON数据返回的配置与实际项目中的应用技巧。
1058 0
|
JSON Java fastjson
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——使用 fastJson 处理 null
本文介绍如何使用 fastJson 处理 null 值。与 Jackson 不同,fastJson 需要通过继承 `WebMvcConfigurationSupport` 类并覆盖 `configureMessageConverters` 方法来配置 null 值的处理方式。例如,可将 String 类型的 null 转为 &quot;&quot;,Number 类型的 null 转为 0,避免循环引用等。代码示例展示了具体实现步骤,包括引入相关依赖、设置序列化特性及解决中文乱码问题。
718 0
|
JSON Java fastjson
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——Spring Boot 默认对Json的处理
本文介绍了在Spring Boot中返回Json数据的方法及数据封装技巧。通过使用`@RestController`注解,可以轻松实现接口返回Json格式的数据,默认使用的Json解析框架是Jackson。文章详细讲解了如何处理不同数据类型(如类对象、List、Map)的Json转换,并提供了自定义配置以应对null值问题。此外,还对比了Jackson与阿里巴巴FastJson的特点,以及如何在项目中引入和配置FastJson,解决null值转换和中文乱码等问题。
1835 0
|
人工智能 安全 Dubbo
Spring AI 智能体通过 MCP 集成本地文件数据
MCP 作为一款开放协议,直接规范了应用程序如何向 LLM 提供上下文。MCP 就像是面向 AI 应用程序的 USB-C 端口,正如 USB-C 提供了一种将设备连接到各种外围设备和配件的标准化方式一样,MCP 提供了一个将 AI 模型连接到不同数据源和工具的标准化方法。
10333 120
|
12月前
|
JSON Java 数据格式
Spring Boot返回Json数据及数据封装
在Spring Boot中,接口间及前后端的数据传输通常使用JSON格式。通过@RestController注解,可轻松实现Controller返回JSON数据。该注解是Spring Boot新增的组合注解,结合了@Controller和@ResponseBody的功能,默认将返回值转换为JSON格式。Spring Boot底层默认采用Jackson作为JSON解析框架,并通过spring-boot-starter-json依赖集成了相关库,包括jackson-databind、jackson-datatype-jdk8等常用模块,简化了开发者对依赖的手动管理。
882 3
|
存储 运维 Java
使用 @Audited 增强Spring Boot 应用程序的数据审计能力
【7月更文挑战第19天】在Spring Boot应用中使用`@Audited`增强数据审计能力涉及在相关实体或方法上添加该注解以标记需审计的操作。例如,在`User`类的`updateUser`方法上使用`@Audited`可记录更新操作的详情。此外,还需配置审计日志存储方式(如数据库)及事件过滤规则等。这有助于满足合规性需求、故障排查及数据分析,对数据安全和完整至关重要。
364 1
|
存储 NoSQL Java
使用Java和Spring Data构建数据访问层
本文介绍了如何使用 Java 和 Spring Data 构建数据访问层的完整过程。通过创建实体类、存储库接口、服务类和控制器类,实现了对数据库的基本操作。这种方法不仅简化了数据访问层的开发,还提高了代码的可维护性和可读性。通过合理使用 Spring Data 提供的功能,可以大幅提升开发效率。
474 21
|
存储 Java API
如何使用 Java 记录简化 Spring Data 中的数据实体
如何使用 Java 记录简化 Spring Data 中的数据实体
293 9