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

Spring通用类型转换的实现原理

Spring通用类型转换的实现原理

    • 设计思路
    • 实现逻辑
      • ConversionService:类型转换服务入口
      • ConverterRegister:转换器注册接口
      • GenericConversionService
        • 1. `Map<ConvertiblePair, GenericConverter> converters`
        • 2. `canConvert()` 与 `convert()`:服务入口
        • 3. `getConverter()`:匹配最合适的转换器
        • 4. `addConverter()` 和 `addConverterFactory()`
        • 5. `getRequiredTypeInfo()`
        • 6. 完整代码

源码见:mini-spring

在这里插入图片描述

设计思路

在前面我们聊了Spring类型转换的三种实现方式,但现在也遇到一个问题,在后续我们将类型转换融入Spring生命周期的时候对于这三种方式如何选择,如何管理。就从这个角度来看的话,是不是还不如只定义一种方式。

对于这个问题Spring也给出了解决方案:

在类型转换系统中保留一个核心注册接口 + 多种适配实现,是 Spring 推荐的设计;但对于业务开发者或自定义扩展场景,通常只需选择一种实现方式(推荐 Converter<S, T>)并注册到统一的转换服务中即可。真正集成到 Spring 生命周期中,核心是统一注册到 ConversionService 中。

可以用以下任意方式注册:

GenericConversionService conversionService = new GenericConversionService();  
conversionService.addConverter(new StringToIntegerConverter());  
Integer integer = conversionService.convert("10", Integer.class);  
Assert.assertEquals(Integer.valueOf(10),integer);  conversionService.addConverterFactory(new StringToNumberConverterFactory());  
Long aLong = conversionService.convert("10", Long.class);  
Assert.assertEquals(Long.valueOf(10),aLong);

统一管理入口:通过 ConversionService 统一进行类型转换调用 ,简单来说就是通过适配器模式将Converter与ConverterFactory封装为GenericConverter。

实现逻辑

ConversionService:类型转换服务入口

public interface ConversionService {  /**  * 检查是否可以将源类型转换为目标类型  *  * @param sourceType 源类型的Class对象  * @param targetType 目标类型的Class对象  * @return 如果可以进行转换则返回true,否则返回false  */    boolean canConvert(Class<?> sourceType, Class<?> targetType);  /**  * 将给定的源对象转换为目标类型  *  * @param source 要转换的源对象  * @param targetType 目标类型的Class对象  * @param <T> 目标类型的泛型参数  * @return 转换后的目标类型对象  */  <T> T convert(Object source, Class<T> targetType);  
}
  • 判断是否支持某种类型对的转换

  • 提供统一的类型转换执行入口

ConverterRegister:转换器注册接口

public interface ConverterRegister {  void addConverter(Converter<?, ?> converter);  void addConverter(GenericConverter genericConverter);  void addConverterFactory(ConverterFactory converterFactory);  
}
  • 三种类型转换器的注册入口

  • 最终都会适配为 GenericConverter 存储

GenericConversionService

Spring 支持三种转换器接口(ConverterConverterFactoryGenericConverter),但使用上不应让开发者关心这些差异。

目的:

  • 将三种接口适配为统一的 GenericConverter 类型

  • 统一注册到一个容器(这里是 Map<ConvertiblePair, GenericConverter>

  • 提供 canConvert()convert() 方法对外暴露转换能力

1. Map<ConvertiblePair, GenericConverter> converters
  • 核心转换器容器:key 是 “源类型 → 目标类型” 的类型对,value 是对应的转换器。
Map<ConvertiblePair, GenericConverter> converters = new HashMap<>();

2. canConvert()convert():服务入口
@Override
public boolean canConvert(Class<?> sourceType, Class<?> targetType)

判断是否存在某种类型转换器(从 sourceType → targetType

@Override
public <T> T convert(Object source, Class<T> targetType)

实际执行转换,内部通过 getConverter() 获取匹配的 GenericConverter


3. getConverter():匹配最合适的转换器
protected GenericConverter getConverter(Class<?> sourceType, Class<?> targetType)

核心逻辑:

  • 递归获取 source 和 target 的继承结构(getClassHierarchy()

  • 生成 ConvertiblePair 对象

  • converters 中查找是否存在该对的转换器

支持子类转父类、接口匹配等灵活匹配机制


4. addConverter()addConverterFactory()
public void addConverter(Converter<?, ?> converter)
  • 将实现了 Converter<S, T> 的对象适配为 GenericConverter(通过 ConverterAdapter

  • 注册到 converters 容器中

public void addConverterFactory(ConverterFactory<?, ?> converterFactory)
  • 同理,适配 ConverterFactoryGenericConverter(通过 ConverterFactoryAdapter

5. getRequiredTypeInfo()
private ConvertiblePair getRequiredTypeInfo(Object object)

这个方法利用 反射 + 泛型解析

  • 读取类所实现的接口的泛型参数类型

  • 自动识别该转换器是支持 S → T 哪两个类型

举例:

class StringToIntegerConverter implements Converter<String, Integer>

会被解析为:

ConvertiblePair(String.class, Integer.class)
6. 完整代码

public class GenericConversionService implements ConversionService, ConverterRegister {  // 用于存储通用转换器  private Map<ConvertiblePair,GenericConverter> converters = new HashMap();  /**  * 检查是否可以将源类型转换为目标类型  *  * @param sourceType 源类型的Class对象  * @param targetType 目标类型的Class对象  * @return 如果可以进行转换则返回true,否则返回false  */    @Override  public boolean canConvert(Class<?> sourceType, Class<?> targetType) {  GenericConverter converter = getConverter(sourceType, targetType);  return converter != null;  }  /**  * 将给定的源对象转换为目标类型  *  * @param source     要转换的源对象  * @param targetType 目标类型的Class对象  * @return 转换后的目标类型对象  */  @Override  public <T> T convert(Object source, Class<T> targetType) {  Class<?> sourceType = source.getClass();  GenericConverter converter = getConverter(sourceType, targetType);  return (T) converter.convert(source, sourceType, targetType);  }  /**  * 获取通用适配器  * @param sourceType  * @param targetType     * @return     */    protected GenericConverter getConverter(Class<?> sourceType, Class<?> targetType){  List<Class<?>> sourceHierarchy = getClassHierarchy(sourceType);  List<Class<?>> targetHierarchy = getClassHierarchy(targetType);  for (Class<?> sourceCandidate : sourceHierarchy) {  for (Class<?> targetCandidate : targetHierarchy) {  ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate);  GenericConverter genericConverter = converters.get(convertiblePair);  if (genericConverter != null){  return genericConverter;  }  }  }  return null;  }  // 获取目标类的完整继承层级结构,以便于通过ConvertiblePair判断转换器是否已注册  protected List<Class<?>> getClassHierarchy(Class<?> clazz){  List<Class<?>>  hierarchy = new ArrayList<>();  while ((clazz != null)){  hierarchy.add(clazz);  clazz = clazz.getSuperclass();  }  return hierarchy;  }  @Override  public void addConverter(Converter<?, ?> converter) {  // 这里传入的是一个Converter转换器对象,我们需要将其转化为GenericConverter对象  ConvertiblePair requiredTypeInfo = getRequiredTypeInfo(converter);  ConverterAdapter converterAdapter = new ConverterAdapter(converter, requiredTypeInfo);  for (ConvertiblePair convertibleType : converterAdapter.getConvertibleTypes()) {  converters.put(convertibleType,converterAdapter);  }  }  @Override  public void addConverterFactory(ConverterFactory converterFactory) {  ConvertiblePair requiredTypeInfo = getRequiredTypeInfo(converterFactory);  ConverterFactoryAdapter converterFactoryAdapter = new ConverterFactoryAdapter(converterFactory, requiredTypeInfo);  for (ConvertiblePair convertibleType : converterFactoryAdapter.getConvertibleTypes()) {  converters.put(convertibleType,converterFactoryAdapter);  }  }  /**  * 获取到目标类所实现的泛型接口的元素  * @param object  * @return     */    private ConvertiblePair getRequiredTypeInfo(Object object){  Type[] types = object.getClass().getGenericInterfaces();  ParameterizedType parameterized = (ParameterizedType) types[0];  Type[] actualTypeArguments = parameterized.getActualTypeArguments();  Class sourceType = (Class) actualTypeArguments[0];  Class targetType = (Class) actualTypeArguments[1];  return new ConvertiblePair(sourceType, targetType);  }  // 通过适配器模式对Converter以及ConverterFactory进行适配  private final class ConverterAdapter implements GenericConverter{  private final Converter converter;  private final ConvertiblePair convertiblePair;  private ConverterAdapter(Converter converter, ConvertiblePair convertiblePair) {  this.converter = converter;  this.convertiblePair = convertiblePair;  }  @Override  public Object convert(Object source, Class sourceType, Class targetType) {  return converter.convert(source);  }  @Override  public Set<ConvertiblePair> getConvertibleTypes() {  return Collections.singleton(convertiblePair);  }  }  private final class ConverterFactoryAdapter implements GenericConverter{  private final ConverterFactory converterFactory;  private final ConvertiblePair convertiblePair;  private ConverterFactoryAdapter(ConverterFactory converterFactory, ConvertiblePair convertiblePair) {  this.converterFactory = converterFactory;  this.convertiblePair = convertiblePair;  }  @Override  public Object convert(Object source, Class sourceType, Class targetType) {  return converterFactory.getConverter(targetType).convert(source);  }  @Override  public Set<ConvertiblePair> getConvertibleTypes() {  return Collections.singleton(convertiblePair);  }  }  
}

相关文章:

  • 红黑树完全指南:为何工程都用它?原理、实现、场景、误区全解析
  • IDEA为何一直无法使用超过4g内存
  • 掌握 HTTP 请求:理解 cURL GET 语法
  • 智警杯备赛--excel模块
  • 【Zephyr 系列 15】构建企业级 BLE 模块通用框架:驱动 + 事件 + 状态机 + 低功耗全栈设计
  • Spring Boot 整合 Apache Flink 的详细过程
  • 黑马Javaweb Request和Response
  • 【数据结构】图论基石:最小生成树(MST)实战精解与Prim/Kruskal算法详解
  • 探索 Shell:选择适合你的命令行利器 bash, zsh, fish, dash, sh...
  • 【学习笔记】深入理解Java虚拟机学习笔记——第3章 垃圾收集器与内存分配策略
  • JVM——对象模型:JVM对象的内部机制和存在方式是怎样的?
  • 嵌入式全栈面试指南:TCP/IP、C 语言基础、STM32 外设与 RT‑Thread
  • 04.管理表
  • iview-admin静态资源js按需加载配置
  • 【JVM面试篇】高频八股汇总——Java内存区域
  • OCCT基础类库介绍: Foundation Classes - Basics
  • 常见查找算法原理与应用详解
  • AURA智能助手在物联网(IoT)和数字化改造领域的使用
  • pandas 字符串存储技术演进:从 object 到 PyArrow 的十年历程
  • 华为IP(8)(OSPF开放最短路径优先)
  • 做网站优化的好处/淘宝关键词指数
  • 免费ppt模板在线下载/seo内容优化方法
  • 常宁网站建设常宁网站建设/百度指数有哪些功能
  • 湘潭网站制作公司/南宁今日头条最新消息
  • 可以做app的网站/长沙百度快照优化排名
  • 做任务领积分兑换别的网站上的会员/网络教学平台