【Spring】java 单体式应用微服务拆分过程 bug 修复:泛型函数
💡简介
- 将单体式 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
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;
}
public static <S, T> T map( { DTORequestParams<S, T> dtoRequestParams)
S source = dtoRequestParams.getSource();
Class<T> targetClass = dtoRequestParams.getTargetClass();
return getMapper().map(source, targetClass);
}
}当使用 feign 进行远程调用时,会报以下错误:
1
2Caused 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]的解决方案,猜测“当参数为泛型数据”的被调用泛型类是无法实现的。
🔨解决
- 通过增加中介转换类实现推理。
- (非常不优雅,但从原理分析似乎也很合理,只是代码很丑)
- (如果有其他优雅的方案,欢迎在留言区告诉我)
🏥反思
- 黑猫白猫,能抓耗子就是好猫。和花一周找一个优雅的方案相比(甚至可能一周也找不到),用一个稍显粗鲁的方案也不失为某种意义上的“优雅”。
- 希望这篇博客对你有帮助!如果你有任何问题或需要进一步的帮助,请随时提问。
- 如果你喜欢这篇文章,欢迎动动小手给我一个follow或star。
🗺参考文献
- 标题: 【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 进行许可。
推荐阅读
评论