首页 > 其他分享 >标题:Dubbo RPC开发中的序列化问题:深度解析反序列化导致的HashMap异常

标题:Dubbo RPC开发中的序列化问题:深度解析反序列化导致的HashMap异常

时间:2023-11-09 21:46:58浏览次数:40  
标签:Dubbo null HashMap 类型 deserializer 序列化 type

Dubbo RPC开发中的序列化问题:深度解析反序列化导致的HashMap异常

在使用Dubbo RPC进行开发时,我们可能会遇到一些出乎意料的问题。其中之一就是在进行远程调用时,内部嵌套对象出现与预期不符的HashMap。这个问题的根源在于反序列化过程中找不到对象,导致解析成了HashMap。在这篇博客中,我们将深入分析这个问题,并通过调试序列化和反序列化的代码来理解其原因。

问题描述

在我们的项目中,有一次我们遇到了这样一个问题:在进行Dubbo RPC调用时,我们发现返回的结果中,一些内部嵌套的对象被转换成了HashMap,而不是我们预期的类型。这个问题在我们的单元测试中没有出现,只在实际的RPC调用中发生。我们希望处理的响应结果是一个List<JobListRpcResponse>,但实际上我们得到的却是一个包含HashMap的List。

解决办法

解决这个问题的方法是手动进行类型转换。我们可以先将对象序列化为JSON字符串,然后再将JSON字符串反序列化为我们需要的类型。如下所示:

List<JobListRpcResponse> jobListRpcResponseList = JSON.parseArray(JSON.toJSONString(jobRpcResponseList), JobListRpcResponse.class);

这样,我们就可以得到我们需要的List<JobListRpcResponse>对象了。

问题本质

问题的本质在于反序列化过程中找不到对象,导致解析成了HashMap。在Dubbo中,序列化和反序列化是通过Hessian库来完成的。Hessian在反序列化对象时,如果找不到对象的类型,就会将对象解析为HashMap。

分析SerializerFactory关键源码

为了理解这个问题,我们需要深入理解Hessian库是如何获取对象的反序列化器的。这个过程是通过SerializerFactory类的getDeserializer方法来完成的。

 

 

 4 public Deserializer getDeserializer(String type) throws HessianProtocolException {
 5     if (type != null && !type.equals("") && !this._typeNotFoundDeserializerMap.containsKey(type)) {
 6         if (this._cachedTypeDeserializerMap != null) {
 7             Deserializer deserializer = (Deserializer)this._cachedTypeDeserializerMap.get(type);
 8             if (deserializer != null) {
 9                 return deserializer;
10             }
11         }
12 13 在这段代码中,首先检查传入的类型(`type`)是否为空,是否为空字符串,以及该类型是否已经在无法找到反序列化器的map(`_typeNotFoundDeserializerMap`)中。如果类型是有效的,并且没有在无法找到反序列化器的map中,那么就尝试从缓存的反序列化器map(`_cachedTypeDeserializerMap`)中获取该类型的反序列化器。如果能够从缓存中获取到反序列化器,那么就直接返回。
14 
15 ```java
16         Deserializer deserializer = (Deserializer)_staticTypeMap.get(type);
17         if (deserializer != null) {
18             return (Deserializer)deserializer;
19         } else {
20 ```
21 如果缓存中没有该类型的反序列化器,那么就尝试从静态类型map(`_staticTypeMap`)中获取反序列化器。静态类型map中存储的是一些预定义的类型和对应的反序列化器。如果能够从静态类型map中获取到反序列化器,那么就直接返回。
22 
23 ```java
24             if (type.startsWith("[")) {
25                 Deserializer subDeserializer = this.getDeserializer(type.substring(1));
26                 if (subDeserializer != null) {
27                     deserializer = new ArrayDeserializer(subDeserializer.getType());
28                 } else {
29                     deserializer = new ArrayDeserializer(Object.class);
30                 }
31             } else if (_unrecognizedTypeCache.get(type) == null) {
32 ```
33 如果类型是一个数组类型(以"["开头),那么就尝试获取数组元素类型的反序列化器。如果能够获取到数组元素类型的反序列化器,那么就创建一个新的数组反序列化器。否则,就创建一个Object类型的数组反序列化器。
34 
35 ```java
36                 try {
37                     Class cl = this.loadSerializedClass(type);
38                     deserializer = this.getDeserializer(cl);
39                 } catch (Exception var4) {
40                     log.warning("Hessian/Burlap: '" + type + "' is an unknown class in " + this._loader + ":\n" + var4);
41                     this._typeNotFoundDeserializerMap.put(type, PRESENT);
42                     log.log(Level.FINER, var4.toString(), var4);
43                     _unrecognizedTypeCache.put(type, new AtomicLong(1L));
44                 }
45             } else {
46                 ((AtomicLong)_unrecognizedTypeCache.get(type)).incrementAndGet();
47                 if (((AtomicLong)_unrecognizedTypeCache.get(type)).get() % 2000L == 0L) {
48                     ((AtomicLong)_unrecognizedTypeCache.get(type)).getAndSet(1L);
49                 }
50             }
51 ```
52 如果类型不是数组类型,那么就尝试加载该类型的类,并获取该类的反序列化器。如果加载类或获取反序列化器失败,那么就将该类型加入到无法找到反序列化器的map中,并记录警告日志。同时,将该类型加入到未识别类型缓存(`_unrecognizedTypeCache`)中,并设置计数为1。如果该类型已经在未识别类型缓存中,那么就增加计数。如果计数达到2000,那么就重置计数为1。
53 
54 ```java
55             if (deserializer != null) {
56                 if (this._cachedTypeDeserializerMap == null) {
57                     this._cachedTypeDeserializerMap = new ConcurrentHashMap(8);
58                 }
59 
60                 this._cachedTypeDeserializerMap.put(type, deserializer);
61             }
62 
63             return (Deserializer)deserializer;
64         }
65     } else {
66         return null;
67     }
68 }
69 ```
70 最后,如果能够获取到反序列化器,那么就将反序列化器加入到缓存的反序列化器map中。然后返回反序列化器。如果类型无效,或者在无法找到反序列化器的map中,那么就返回null。
71 
72 这段代码的关键在于,如果无法找到对应类型的反序列化器,就会将类型加入到无法找到反序列化器的map中。这就是我们在Dubbo RPC调用中,如果无法找到对象的类型,就会将对象解析为HashMap的原因。

 

结论

在使用Dubbo RPC进行开发时,我们需要注意序列化和反序列化过程中可能出现的问题。特别是当我们在RPC调用中传递复杂的对象时,我们需要确保我们正确地进行类型转换,以防止类型信息丢失。同时,我们也需要深入理解Hessian库的工作原理,以便在遇到问题时,能够快速地找到问题的根源。

标签:Dubbo,null,HashMap,类型,deserializer,序列化,type
From: https://www.cnblogs.com/hld123/p/17822933.html

相关文章

  • java8 time to json_Java8 LocalDateTime 如何支持yyyy-MM-dd反序列化
    其实吧,从你的问题描述来看,我觉得你对于LocalDateLocalDateTimeLocalTime之间的区分以及Java8时间API的认识应该足够了,足够可以做一些简单使用的地步了,如果从我们旁观者角度来说,仅仅只是为了改你这个问题,其实之前回答的人都是可以的。比如上官元恒提到的直接把请求对象中的字段类......
  • 开发时推荐使用Map map = new HashMap()
    Mapmap=newHashMap();Map是一个接口,HashMap是具体的实现类。由于接口就是多个类的共有规范(里面的抽象方法),是一种引用数据类型,一个抽象的概念,不能被实例化,因此接口需要由具体的类来实现。这条代码指明:由HashMap类来实现接口Map中描述的方法。HashMapmap=newHashMap(......
  • Java Fastjson反序列化漏洞研究
    一、Fastjson简介Fastjson是阿里巴巴的一个开源项目,在GitHub上开源,使用Apache2.0协议。它是一个支持JavaObject和JSON字符串互相转换的Java库。Fastjson最大的特点在于它的快速,它超越了JackJson、Gson等库。据官方发布的说明,Fastjson从2011年fastjson发布1.1.x版本之后,其性能......
  • HashMap、TreeMap、Hashtable、HashSet和ConcurrentHashMap区别
    一、HashMap和TreeMap区别1、HashMap是基于散列表实现的,时间复杂度平均能达到O(1)。   TreeMap基于红黑树(一种自平衡二叉查找树)实现的,时间复杂度平均能达到O(logn)。2、HashMap、TreeMap都继承AbstractMap抽象类;TreeMap实现SortedMap接口,所以TreeMap是有序的!HashMap是无序的......
  • HashMap---jdk8
    概述HashtablebasedimplementationoftheMapinterface.Thisimplementationprovidesalloftheoptionalmapoperations,andpermits<tt>null</tt>valuesandthe<tt>null</tt>key.(The<tt>HashMap</tt>classis......
  • XMLDecoder反序列化漏洞研究
    一、XMLDecoder简介java.beans.XMLDecoder是jdk自带的以SAX方式解析XML的类,主要功能是实现java对象和xml文件之间的转化:序列化:将java对象转换成xml文件反序列化:把特定格式的xml文件转换成java对象下面是一个简单地demo样例,Person.javapackageorg.example;publiccla......
  • hashmap的小应用---投票去旅游
    在学习了map之后,使用简单的hashmap进行简单的全班同学投票旅游地点packagecom.itheima.myMap;importjava.util.*;importjava.util.function.BiConsumer;publicclassText2{publicstaticvoidmain(String[]args){//模拟投票Randomra=newRandom......
  • LinkedHashMap
    概述Hashtableandlinkedlistimplementationofthe<tt>Map</tt>interface,withpredictableiterationorder.Thisimplementationdiffersfrom<tt>HashMap</tt>inthatitmaintainsadoubly-linkedlistrunningthroughallofitsen......
  • 使用 JSON JavaScriptSerializer 进行序列化或反序列化时出错。字符串的长度超过了为
    一个报表的查询,用ajax调用的Service,查询条件没有问题,后台也能返回数据,就一直返回Error提示,F12看到是因为返回json时出错了 在web.config的configuration加以下代码即可解决<system.web.extensions><scripting><webServices><jsonSerializationmaxJs......
  • 19.7 Boost Asio 传输序列化数据
    序列化和反序列化是指将数据结构或对象转换为一组字节,以便在需要时可以将其存储在磁盘上或通过网络传输,并且可以在需要时重新创建原始对象或数据结构。序列化是将内存中的对象转换为字节的过程。在序列化期间,对象的状态被编码为一组字节,并可以保存或传输到另一个位置。序列化后的......