当前位置: 首页 > news >正文

Spring类型转换器相关接口和实现原理

Spring类型转换器相关接口和实现原理

    • 一、核心组件
      • 1. `ConversionService`(核心接口)
      • 2. `Converter<S, T>`
      • 3. `GenericConverter`
      • 4. `ConverterFactory<S, R>`
    • 二、底层实现
      • 1,普通类型转换器 Converter<S, T>
      • 2,类型转换工厂 ConverterFactory<S, R>
      • 3,通用类型转换器 GenericConverter

源码见:mini-spring

在这里插入图片描述

Spring 的 类型转换(Type Conversion) 是指:在应用中将一种 Java 类型的对象转换成另一种类型对象的机制。

在实际开发中,我们经常会遇到“类型不匹配”问题,比如:

  • 表单提交的字符串要转换成数字、日期、枚举等;

  • 配置文件中的字符串要转换成 Boolean、List、Class;

  • Bean 属性注入时类型不一致;

  • SpEL 表达式中的值需要自动转换类型;

  • 数据绑定(如 Web MVC 参数绑定)中,request 参数是字符串,要绑定到业务对象中。

Spring 提供了统一的类型转换框架来处理这些场景。

本节就Spring如何实现类型转换展开叙述,下节介绍如何将其融入生命周期当中

一、核心组件

1. ConversionService(核心接口)

Spring 类型转换的核心服务接口,负责执行类型之间的转换:

public interface ConversionService {boolean canConvert(Class<?> sourceType, Class<?> targetType);<T> T convert(Object source, Class<T> targetType);
}
  • 可以检查是否支持某种转换。
  • 可以执行实际的转换。

2. Converter<S, T>

这是最基本的类型转换器接口,Spring 中的所有类型转换器都实现了该接口:

public interface ConversionService {boolean canConvert(Class<?> sourceType, Class<?> targetType);<T> T convert(Object source, Class<T> targetType);
}
  • S:源类型
  • T:目标类型

例如,将字符串转为整数的转换器:

public class StringToIntegerConverter implements Converter<String, Integer> {public Integer convert(String source) {return Integer.valueOf(source);}
}

3. GenericConverter

更灵活但也更复杂的转换器,适合处理多个源/目标类型的场景:

public class StringToIntegerConverter implements Converter<String, Integer> {public Integer convert(String source) {return Integer.valueOf(source);}
}
  • 支持多个源类型与目标类型组合。

  • 使用 TypeDescriptor 解决泛型、注解等更复杂的类型问题。


4. ConverterFactory<S, R>

适用于一组相关类型转换的情况。例如:String 转为 Enum 的所有子类型:

public interface ConverterFactory<S, R> {<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}

二、底层实现

在上一节中,我们简要了解了类型转换的核心组件。实际上,Spring 提供了三种不同类型的转换器接口:

  • 普通类型转换器(Converter
  • 类型转换工厂(ConverterFactory
  • 通用类型转换器(GenericConverter

下面将逐一进行讲解。

1,普通类型转换器 Converter<S, T>

public interface Converter<S,T> {  T convert(S source);  
}

该接口结构非常简洁,只定义了一个核心方法 convert,用于将源类型 S 转换为目标类型 T。使用时只需实现此接口并提供具体的转换逻辑即可。

例如,将 String 转换为 Integer

public class StringToIntegerConverter implements Converter<String,Integer> {  @Override  public Integer convert(String source) {  return Integer.valueOf(source);  }  
}

测试一下

@Test  
public void testStringToIntegerConverter(){  StringToIntegerConverter converter = new StringToIntegerConverter();  Integer integer = converter.convert("10");  Assert.assertEquals(Integer.valueOf(10),integer);  
}

2,类型转换工厂 ConverterFactory<S, R>

相较于 Converter 接口,ConverterFactory 适用于更广泛的转换需求。它可以通过工厂方法,为某一源类型 S 生成多个不同目标子类型 R 的转换器,常用于统一处理一组目标类型。

public interface ConverterFactory<S, R> {  /**  * 根据目标类型获取转换器对象  *  * @param <T> 目标类型参数,表示具体的转换后数据类型,必须是R类型或其子类型  * @param targetType 目标类型的Class对象,用于指定转换后的数据类型  * @return 返回一个Converter对象,用于将源数据类型S转换为目标类型T  */    <T extends R> Converter<S,T> getConverter(Class<T> targetType);  
}

以下是一个将 String 转换为多个数字类型(如 IntegerLong)的工厂实现:

public class StringToNumberConverterFactory implements ConverterFactory<String,Number> {  /**  * 根据目标类型获取转换器对象  *  * @param targetType 目标类型的Class对象,用于指定转换后的数据类型  * @return 返回一个Converter对象,用于将源数据类型S转换为目标类型T  */ @Override  public <T extends Number> Converter<String, T> getConverter(Class<T> targetType) {  return new StringToNumber<T>(targetType);  }  public static final class StringToNumber<T extends Number> implements  Converter<String,T>{  private final Class<T> targetType;  public StringToNumber(Class<T> targetType) {  this.targetType = targetType;  }  @Override  public T convert(String source) {  if (source.length() == 0){  return  null;  }  if (targetType.equals(Integer.class)){  return (T) Integer.valueOf(source);  } else if (targetType.equals(Long.class)) {  return (T) Long.valueOf(source);  }else {  throw new IllegalArgumentException(  "Cannot convert String [" + source + "] to target class [" + targetType.getName() + "]");  }  }  }  
}

测试一下

@Test  
public void testStringToNumberConverterFactory(){  StringToNumberConverterFactory converterFactory = new StringToNumberConverterFactory();  Converter<String, Integer> converter = converterFactory.getConverter(Integer.class);  Integer integer = converter.convert("10");  Assert.assertEquals(Integer.valueOf(10),integer);  
}

3,通用类型转换器 GenericConverter

GenericConverter 是 Spring 提供的最灵活、功能最强大的转换接口,适用于更复杂的场景,包括:

  • 支持多个源类型和目标类型的转换(如 String → List<Integer>String → Set<String>);
  • 利用运行时类型信息(通过 TypeDescriptor)进行精确判断;
  • 适配泛型、注解、字段等更复杂的上下文信息。
public interface GenericConverter {  // 执行类型转换逻辑  Object convert(Object source, Class sourceType, Class targetType);  // 获取到对应的ConvertiblePair配对关系对象  Set<ConvertiblePair> getConvertibleTypes();  /**  * 用于管理“源类型”和“目标类型”的配对关系  */  public static final class ConvertiblePair{  private final Class<?> sourceType;  private final Class<?> targetType;  public ConvertiblePair(Class<?> sourceType, Class<?> targetType) {  this.sourceType = sourceType;  this.targetType = targetType;  }  public Class<?> getSourceType() {  return sourceType;  }  public Class<?> getTargetType() {  return targetType;  }  @Override  public boolean equals(Object object) {  if (object == null || getClass() != object.getClass()) return false;  ConvertiblePair that = (ConvertiblePair) object;  return Objects.equals(sourceType, that.sourceType) && Objects.equals(targetType, that.targetType);  }  @Override  public int hashCode() {  return Objects.hash(sourceType, targetType);  }  }  
}

我们可以看到在GenericConverter我们还定义了一个静态的内部类ConvertiblePair,该类是用来用于管理“源类型”和“目标类型”的配对关系。

简单来说,我们来思考一个问题当我们调用GenericConverter的convert去尝试转换类型,而GenericConverter是一个接口,具体的各种转换逻辑由子类实现,那我们又如何才能判断出,我要转换的类型是否合法,当前类型转换器当中是否支持?

所以这里就引入了ConvertiblePair用来表示一个“源类型 → 目标类型”的一组转换类型

测试一下

@Test  
public void testGenericConverter(){  StringToBooleanConverter converter = new StringToBooleanConverter();  Boolean aTrue =(Boolean)  converter.convert("true", String.class, Boolean.class);  Assert.assertTrue(aTrue);  
}

相关文章:

  • LLMs 系列科普文(8)
  • 免费批量PDF转Word工具
  • MyBatis原理剖析(一)
  • Vue ⑤-自定义指令 || 插槽
  • SCADA|RESTful学习,Apipost通过GET获取KingSCADA实时数据
  • LeetCode - 53. 最大子数组和
  • 哈佛总线架构是什么?
  • Linux(Centos 7.6)命令详解:which
  • Web前端开发:JavaScript中的eval()函数
  • C语言基础面试问答
  • springboot线上教学平台
  • c++ 头文件
  • 构建AI中台:从技术孤岛到智能服务能力平台化
  • VB调用CryReport指南方案
  • Linux操作系统Shell脚本企业级综合练习
  • 如何计算1920*1080分辨率的YUV或RGB图像数据占用大小?
  • 2978: 临时测试-页码
  • 如何禁用windows server系统自动更新并防止自动重启
  • 非Root用户启动SSH服务经验小结
  • AtCoder Beginner Contest 409(ABCDEF)
  • 怀化订水网站/百度站长资源
  • 网站推广效益怎么分析/百家号关键词排名优化
  • 黄州做网站的/2021十大网络舆情案例
  • 忻州宁武网站建设/网站建设优化哪家公司好
  • 做网站做的好的公司有哪些/网络营销制度课完整版
  • 北京建设官网证书查询/搜索引擎优化是免费的吗