微服务远程调用参数莫名丢失

1)问题描述

服务A ServiceA 远程调用服务B ServiceB(HttpClient/RestTemplet/Fegin等方式)

调用参数简单描述如下

//组装参数,大致如下,忽略处理细节
Customer c1 = new Customer();
Map map1 = new HashMap();
map1.put('user1',c1);

Customer c2 = new Customer();
Map map2 = new HashMap();
map2.put('user2',c2);

Map map3 = new HashMap();
map3.putAll(map2);

List paramList = new ArrayList();
paramList.add(map1);
paramList.add(map2);
paramList.add(map3);

//发起调用
ServiceA.invokeServiceB(paramList);

2)问题现象

调用至 ServiceB,接收的参数中 paramList 第三个元素为null,莫名缺失。

2023-05-13 16:58:10.460  INFO 14508 --- [nio-8081-exec-1] c.t.v1.controller.ProductInfoController  : param:[{"user1":{"accountId":"001","addr":"001-addr","age":10,"name":"001-name"}},{"user2":{"accountId":"002","addr":"002-addr","age":20,"name":"002-name"}},{"user2":{"$ref":"$[1].user2"}}]

3)原因分析

i)Java远程调用(HttpClient/RestTemplet/Feign等等)无论通过何种方式调用,最终都是需要序列化后,以字节的形式传输。

i)Java对象序列化时,若包含重复的对象(相同引用),则只会序列化一次,其他的仅使用句柄。

i)Map.putAll()方法是浅拷贝。

结合以上三点,问题根源解释如下:

入参 map3是通过map.putAll()赋值,因此map3\map2 实际都是同一个对象 Customer c2,

paramList 序列化时,只会处理 map1,map2。map3不会做序列化,仅使用map2的句柄。

所以,ServiceB 处理请求,对参数反序列化时,由于map3为句柄,且ServiceB中未定义Customer对象,从而无法反序列化,导致参数缺失。

4)解决方案

远程调用时,若同一个对象可能出现多次,则需通过深拷贝创建新的对象,再进行调用。本例修改示意如下:

//组装参数,大致如下,忽略处理细节
Customer c1 = new Customer();
Map map1 = new HashMap();
map1.put('user1',c1);

Customer c2 = new Customer();
Map map2 = new HashMap();
map2.put('user2',c2);

//利用JSONObject实现深拷贝
Map map3 = JSONObeject.parseObject( JSONObject.toJSONString(map2),Map.class );

List paramList = new ArrayList();
paramList.add(map1);
paramList.add(map2);
paramList.add(map3);

//发起调用
ServiceA.invokeServiceB(paramList);

5)问题延申

问题1. 假若入参paramList中Map存放的不是自定义对象,而是int、String等类型,如下方式能正常反序列化吗?

//组装参数,大致如下,忽略处理细节
Map map1 = new HashMap();
map1.put('age',20);
map1.put('addr',"北京");

Map map2 = new HashMap();
map2.put('age',30);
map2.put('addr',"上海");

List paramList = new ArrayList();
paramList.add(map1);
paramList.add(map2);
paramList.add(map2);

//发起调用
ServiceA.invokeServiceB(paramList);

问题2. 假若在ServiceA,ServiceB中各自定义了Customer对象,且属性完全一致。(使用浅拷贝传参)最终能正常反序列化吗?

问题3. 假若自定义对象Customer 定义在公共组件common中,ServiceA,ServiceB均引用了common组件。(使用浅拷贝传参)最终能正常反序列化吗?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值