hessian序列化源码分析

简介:

  1. 背景

    最近在处理一个hessian的反序列化问题时,因为服务端使用了pojo bean中多了一个enum属性,导致客户端在反序列化时疯狂的在打印日志。警告说找不到对应的enum class,因为项目中本身是设置了log4j的根输出为一个文件。 

    比较奇怪的是,hessian对应的日志输出全都打印到了控制台(虽然我们对console进行了重定向输出),导致对应的文件达到几百MB。无奈之下,仔细分析了下hessian的源码。

介绍

 

先看一张hessian主要的几个概念图

说明:

 

  1. Serializer  序列化的接口
  2. Deserializer 反序列化的接口
  3. AbstractHessianInput  hessian自定义的输入流,提供对应的read各种类型的方法
  4. AbstractHessianOutput  hessian自定义的输出流,提供对应的write各种类型的方法

 

AbstractSerializerFactory介绍

serializerFactory从字面意思上也看的出来,是管理和维护对应序列化/反序列化机制的工厂。默认的几种实现

 

  • SerializerFactory 标准的实现
  • ExtSerializerFactory 我们可以设置自定义的序列化机制,通过该Factory可以进行扩展。
  • BeanSerializerFactory 对SerializerFactory的默认object的序列化机制进行强制指定,指定为BeanSerializer。 具体BeanSerializer的实现后面再表。
自定义序列化机制的扩展:
  1. 实现Serializer/Deserializer接口
1.ExtSerializerFactory extSerializerFactory = new ExtSerializerFactory();  
2.extSerializerFactory.addSerializer(class , mySerializer); //添加自定义的序列化接口  
3.extSerializerFactory.addDeserializer(class , myDeserializer); //添加自定义的反序列化接口  
4.  
5.serializerFactory.addFactory(extSerializerFactory); //注册ext到序列化工厂  

SerializerFactory介绍:
先看一下hesian提供的Serializer/Derializer几种默认实现

 







具体的实现就不细说,有兴趣的自己看代码去。
下面提一下我在看得过程中比较在意和疑惑过的点。

1.  Object对象的序列化/反序列化
答:JavaSerializer或者BeanSerializer。这两者的区别

 

  • JavaSerializer是通过反射获取所有bean的属性进行序列化,排除static和transient属性,对其他所有的属性进行递归序列化处理(比如属性本身是个对象)。
  • BeanSerializer是遵循pojo bean的约定,扫描bean的所有方法,发现存在get和set方法的属性进行序列化,它并不直接直接操作所有的属性,比较温柔。 注意:BeanSerializer将会无法处理你的boolean属性,因为通过默认的eclipse生成的方法是以isXXX打头,不会被序列化。
2.  枚举对象的序列化/反序列化
答:看过类图后,就很明显的发现存在一个EnumSerializer和EnumDeserializer实现。大家都知道枚举对象全都继承于enum对象,所以EnumSerializer会反射调用name方法,EnumDeserializer是反射调用valueof方法。这样就很明显了,如果服务端多了一个枚举值定义, 客户端反序列化会出现异常,不会是一个兼容的过程。

 

补充:测试过程中,hessian 3.1.3版本存在enum序列化问题,低级的问题。

 
3.  服务端抛异常后的序列化/反序列化
答:这个也是在做rpc调用,一个比较容易被遗忘的点,只关注了正常的业务功能的流程,却没有考虑对应的异常处理的序列化和反序列化。hessian提供了ThrowableSerializer和StackTraceElementDeserializer进行序列化处理。
  • ThrowableSerializer会按照object的序列化方式,传递对应的信息到客户端。包括stackTrace和detailMessage等。
  • StackTraceElementDeserializer反序列化对应的异常栈信息。异常的其他属性通过JavaSerializer进行反序列化处理。
补充:测试过程中,hessian 3.0.20,3.1.3版本存在问题,异常的反序列化在hessian 1.0协议是正常的,到2.0就会出现错误。 具体的问题也有人报告了bug :  http://maillist.caucho.com/pipermail/hessian-interest/2008-February/000297.html ,升级到3.1.5之后就解决了.

测试代码

1.public static void exceptionTest() throws Exception {  
2.    Exception exception = null;  
3.    try {  
4.        FileInputStream stream = new FileInputStream("notfound");  
5.    } catch (FileNotFoundException e) {  
6.        exception = e;  
7.    }  
8.  
9.    ByteArrayOutputStream bos = new ByteArrayOutputStream();  
10.    HessianOutput out = new HessianOutput(bos);  
11.    out.writeObject(exception);  
12.    out.flush();  
13.  
14.    byte[] bytes = bos.toByteArray();  
15.    ByteArrayInputStream bin = new ByteArrayInputStream(bytes);  
16.    HessianInput in = new HessianInput(bin);  
17.    Exception read = (Exception) in.readObject(FileNotFoundException.class);  
18.    read.printStackTrace();  
19.    System.out.println(read);  
20.}  

hessian支持对流进行压缩处理,可以看下 Deflation

1.Hessian2Output out = new Hessian2Output(bos);  
2.out = envelope.wrap(out); //包装为压缩  
3.  
4.Hessian2Input in = new Hessian2Input(bin);  
5.in = envelope.unwrap(in); //解缩

压缩慎用,在测试过程中有一些磕磕碰碰的小问题。 

后记

hessian序列化机制的性能比较,后续补上。 主要是和原先的几种序列化协议相关数据对比

 

序列化数据对比


bytes字节数对比


具体的数字: 

  protobuf jackson xstream Serializable hessian2 hessian2压缩 hessian1
序列化(单位ns) 1154 5421  92406  10189 26794 100766 29027
反序列化(单位ns) 1334 8743  117329  64027 37871 188432 37596
bytes 97 311  664  824 374 283 495

相关文章
|
2月前
|
JSON fastjson Java
niubility!即使JavaBean没有默认无参构造器,fastjson也可以反序列化。- - - - 阿里Fastjson反序列化源码分析
本文详细分析了 Fastjson 反序列化对象的源码(版本 fastjson-1.2.60),揭示了即使 JavaBean 沲有默认无参构造器,Fastjson 仍能正常反序列化的技术内幕。文章通过案例展示了 Fastjson 在不同构造器情况下的行为,并深入探讨了 `ParserConfig#getDeserializer` 方法的核心逻辑。此外,还介绍了 ASM 字节码技术的应用及其在反序列化过程中的角色。
76 10
|
3月前
|
Java
JDK序列化原理问题之Hessian框架不支持writeObject/readObject方法如何解决
JDK序列化原理问题之Hessian框架不支持writeObject/readObject方法如何解决
|
3月前
|
XML 存储 JSON
(十二)探索高性能通信与RPC框架基石:Json、ProtoBuf、Hessian序列化详解
如今这个分布式风靡的时代,网络通信技术,是每位技术人员必须掌握的技能,因为无论是哪种分布式技术,都离不开心跳、选举、节点感知、数据同步……等机制,而究其根本,这些技术的本质都是网络间的数据交互。正因如此,想要构建一个高性能的分布式组件/系统,不得不思考一个问题:怎么才能让数据传输的速度更快?
|
测试技术 Go
gRPC源码分析(四):剖析Proto序列化
首先,针对读源码是先看源代码还是测试代码,因人而异。个人建议在对源码毫无头绪时,先从测试入手,了解大致功能;如果有一定基础,那么也可以直接入手源代码。我认为优秀的Go源码可读性是非常高的,所以一般情况下,我都直接从源文件入手,遇到问题才会去对应的测试里阅读。
124 1
|
安全 测试技术 Nacos
Nacos Jraft Hessian反序列化远程代码执行漏洞
Nacos Jraft Hessian反序列化远程代码执行漏洞
1765 1
|
存储 分布式计算 JavaScript
Fury系列(四):一个比Kryo/Hessian快30~40倍的类型前后兼容序列化器
问题背景类型前后兼容是复杂业务场景序列化的常见需求。在快速迭代的业务场景当中,读写端经常发生对象字段发生变更:在线应用场景:线上SOFA/HSF应用提供服务给多个调用方,服务的滚动升级以及各个调用方独立更新都可能导致对象类型不一致的情况;在线服务场景:在线服务框架常驻不更改对象类型,但调用方业务逻辑变动独立更新导致对象字段跟服务端不一致;对象持久化场景:对象数据序列化后持久化写入存储(如Spark
1588 2
Fury系列(四):一个比Kryo/Hessian快30~40倍的类型前后兼容序列化器
|
Dubbo 算法 安全
Java序列化案例demo(包含Kryo、JDK原生、Protobuf、ProtoStuff以及hessian)(二)
Java序列化案例demo(包含Kryo、JDK原生、Protobuf、ProtoStuff以及hessian)(二)
Java序列化案例demo(包含Kryo、JDK原生、Protobuf、ProtoStuff以及hessian)(二)
|
SQL 存储 Java
Java序列化案例demo(包含Kryo、JDK原生、Protobuf、ProtoStuff以及hessian)(一)
Java序列化案例demo(包含Kryo、JDK原生、Protobuf、ProtoStuff以及hessian)(一)
Java序列化案例demo(包含Kryo、JDK原生、Protobuf、ProtoStuff以及hessian)(一)
|
XML Java 程序员
zookeeper源码分析--序列化篇
zookeeper源码分析--序列化篇
174 0