当前位置: 首页 > 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);  
}
http://www.xdnf.cn/news/942643.html

相关文章:

  • 【JavaScript】利用`localStorage`实现多窗口数据交互同步【附完整源码】
  • OD 算法题 B卷【删除字符串中出现次数最少的字符】
  • 如何禁用windows server系统自动更新并防止自动重启
  • 推理式奖励模型:使用自然语言反馈改进强化学习效果
  • 卫星接收天线G/T值怎么计算?附G/T计算excel表格链接
  • 打卡day48
  • 12.7Swing控件5 JProgressBar
  • Spring AI中使用ChatMemory实现会话记忆功能
  • 算法打卡第18天
  • 【CUDA 】第5章 共享内存和常量内存——5.3减少全局内存访问(2)
  • Linux 环境配置
  • 【立体匹配】:双目立体匹配SGBM:(1)运行
  • 深入解析JavaScript构造函数与原型链
  • JavaScript 自定义对象详解
  • AI医生时代来临!o1模型在医疗诊断中超越人类医生
  • 查看进程线程的方法
  • 进制符号表示
  • 【阿里巴巴 x 浙江大学】信息与交互设计 - 信息设计漫谈
  • AIGC 基础篇 Python基础 02
  • MS8312A 车规 精密、低噪、CMOS、轨到轨输入输出运算放大器,用于传感器、条形扫描器
  • arxir网址自动转向国内镜像
  • 【DTOF传感器】光子飞行时间传感技术
  • 通信之光端机
  • 苏超 - 江苏省城市足球联赛
  • Angular中Webpack与ngx-build-plus 浅学
  • 【刷题模板】链表、堆栈
  • AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年6月8日第102弹
  • 06. C#入门系列【自定义类型】:从青铜到王者的进阶之路
  • 星耀8上市品鉴暨北京中和吉晟吉利银河用户中心开业媒体见面会
  • 免费批量去水印工具 - 针对文心一言生成图片