【Spring】java 单体式应用微服务拆分过程 bug 修复:泛型函数

【Spring】java 单体式应用微服务拆分过程 bug 修复:泛型函数

Fre5h1nd Lv5

💡简介

  • 将单体式 Spring 应用拆分为微服务式应用过程中,遇到了一系列有关 Spring 框架的问题,将修复过程及相关问题信息分析过程记录下来,便于以后解决同类问题,也顺便提高自己对 Spring 框架的理解。

🧠问题

  • 存在一个泛型函数,其输入参数和返回值都是泛型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @RestController
    @RequestMapping("/DTOUtil")
    public class DTOUtil {

    private static ModelMapper MAPPER = null;

    private static ModelMapper getMapper() {
    if (MAPPER == null) {
    MAPPER = new ModelMapper();
    MAPPER.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
    }

    return MAPPER;
    }

    @RequestMapping(value = "/map", method = RequestMethod.POST)
    @ResponseBody
    public static <S, T> T map(@RequestBody DTORequestParams<S, T> dtoRequestParams) {
    S source = dtoRequestParams.getSource();
    Class<T> targetClass = dtoRequestParams.getTargetClass();
    return getMapper().map(source, targetClass);
    }
    }
  • 当使用 feign 进行远程调用时,会报以下错误:

    1
    2
    Caused by: feign.FeignException: status 400 reading DTOUtilRealClient#map(DTORequestParams); content:
    {"timestamp":1694347613202,"status":400,"error":"Bad Request","exception":"org.springframework.http.converter.HttpMessageNotReadableException","message":"Bad Request","path":"/DTOUtil/map"}

📚信息搜集

泛型原理[1]

  • 泛型的本质是对类型进行参数化,在代码逻辑不关注具体的数据类型时使用。例如:实现一个通用的排序算法,此时关注的是算法本身,而非排序的对象的类型。

  • 基本原理:

    • 泛型本质是将数据类型参数化,它通过擦除的方式来实现。
      • 声明了泛型的 .java 源代码,在编译生成 .class 文件之后,泛型相关的信息就消失了。可以认为,源代码中泛型相关的信息,就是提供给编译器用的。泛型信息对 Java 编译器可以见,对 Java 虚拟机不可见。
    • Java 编译器通过如下方式实现擦除:
      • 用 Object 或者界定类型替代泛型,产生的字节码中只包含了原始的类,接口和方法;
      • 在恰当的位置插入强制转换代码来确保类型安全;
      • 在继承了泛型类或接口的类中插入桥接方法来保留多态性。

Feign与泛型

  • 个人分析:

    • 基于上一节原理,在源码编译后泛型相关信息就已经被翻译为具体类型。
      • 因此当被调用的泛型类被单独封装在一个微服务中时,编译器无法推断应当翻译为什么类(每个微服务单独编译,不知道会被谁调用)。
      • 这种情况下似乎只能放弃使用泛型类,而是增加更具体的接口。考虑增加一个转换器类作为中介来进行类型的转换。
  • 经过广泛调研,看到多个“当返回值为泛型数据”[2][3]的解决方案,猜测“当参数为泛型数据”的被调用泛型类是无法实现的。

🔨解决

  • 通过增加中介转换类实现推理。
  • (非常不优雅,但从原理分析似乎也很合理,只是代码很丑)
  • (如果有其他优雅的方案,欢迎在留言区告诉我)

🏥反思

  1. 黑猫白猫,能抓耗子就是好猫。和花一周找一个优雅的方案相比(甚至可能一周也找不到),用一个稍显粗鲁的方案也不失为某种意义上的“优雅”。


  • 希望这篇博客对你有帮助!如果你有任何问题或需要进一步的帮助,请随时提问。
  • 如果你喜欢这篇文章,欢迎动动小手给我一个follow或star。

🗺参考文献

[1] Java 中泛型的实现原理

[2] FeignClient使用泛型接收数据

[3] Feign 踩坑指南 (接口返回泛型设置属性为null)

  • 标题: 【Spring】java 单体式应用微服务拆分过程 bug 修复:泛型函数
  • 作者: Fre5h1nd
  • 创建于 : 2023-09-08 15:43:21
  • 更新于 : 2023-09-11 20:17:09
  • 链接: https://freshwlnd.github.io/2023/09/08/program_language/java/java-spring-feign-generic/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
【Spring】java 单体式应用微服务拆分过程 bug 修复:泛型函数