4

Hessian 协议解释与实战(五):对象与映射

 2 years ago
source link: https://www.diguage.com/post/hessian-protocol-interpretation-and-practice-5/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Hessian 协议解释与实战(五):对象与映射

2022-05-31
Hessian 协议解释与实战(五):对象与映射

前段时间,翻译了 Hessian 2.0 的序列化协议,发布在了 Hessian 2.0 序列化协议(中文版)。但是,其中有很多言语不详之处。所以,接下来会用几篇文章来详细解释并实践一下 Hessian 序列化协议,以求做到知其然知其所以然。目录如下:

  1. Hessian 协议解释与实战(一):布尔、日期、浮点数与整数 — 介绍布尔型数据、日期类型、浮点类型数据和整数类型数据等四种类型的数据的处理。

  2. Hessian 协议解释与实战(二):长整型、二进制数据与 Null — 介绍长整数类型数据、二进制数据和 null 等三种类型的数据的处理。

  3. Hessian 协议解释与实战(三):字符串 — 专门介绍了关于字符串的处理。由于字符串需要铺垫的基础知识比较多,处理细节也有繁琐,所以单独成篇来介绍。

  4. Hessian 源码分析(Java) — 开始第四篇分析之前,先来介绍一下 Hessian 的源码实现。方便后续展开说明。

  5. Hessian 协议解释与实战(四):数组与集合 — 铺垫了一些关于实例对象的处理,重点介绍关于数组和集合的相关处理。

  6. Hessian 协议解释与实战(五):对象与映射 — 重点介绍关于对象与映射的相关处理。

  7. 未完待续,敬请继续关注 "地瓜哥"博客网

在上一篇文章 Hessian 协议解释与实战(四):数组与集合 中研究了数组和集合的处理方式。接下来介绍对象和映射的处理。

基础工具方法

基础工具方法就不再赘述,请直接参考 Hessian 协议解释与实战(一):基础工具方法 中提到的几个方法。

另外,在 Hessian 协议解释与实战(四):数组与集合 中,又对一些方法做了扩展和更新。

下面,我们来看一看映射的处理。

坦白讲,个人觉得 Hessian 2.0 序列化协议(中文版):映射 的协议定义写的非常模糊。倒是给的示例,还可圈可点。

相关代码实现

通过 Hessian 源码分析(Java) 可以指定, MapSerializer 是处理映射的 Serializer。所以,只需要关注一下 MapSerializer 就可以对映射的处理一目了然。结合代码,可以看出,映射的序列化流程大致如下:

  1. AbstractHessianOutput.writeMapBegin(String type) — 写入映射起始信息;

  2. 遍历 Map.Entry,并且是先序列化 Key,然后序列化 Value;

  3. AbstractHessianOutput.writeMapEnd() — 写入映射结束信息。

另外,在 Hessian 源码分析(Java) 中,也提到在 Hessian2Output 中实现了 AbstractHessianOutput 的接口。所以,只需要关注 Hessian2Output 对上述方法的实现即可。

Hessian2Output 中可以看出:

  1. Hessian2Output.writeMapBegin(String type) 有两个类型:

    1. 需要写入类型: M,前置标志位后是映射类型信息;

    2. 不需要写入类型: H,这里没有写入类型信息。

  2. AbstractHessianOutput.writeMapEnd() — 映射结束信息只有一个结束标志位: Z。这个标志位,在 Hessian 协议解释与实战(四):数组与集合: Collection<Integer>.iterator 👉 IteratorSerializer 中也用到了。

下面开始做实验来验证。

HashMap

接下来,我们看一下序列化操作:

从结果上来看,跟我们上面的分析差不多,确定了一些细节:

  1. 首先,写入前置标志位 0x48H

  2. 其次,遍历 Map.Entry,并将其序列化

    1. Value

  3. 最后,写入结束标志位 0x5AZ)。

接下来再看看其他类型的 Map 的处理情况。

TreeMap

来看看 TreeMap 的处理情况:

针对 TreeMap 的处理,大致也可以分为三步:

  1. 首先,写入前置信息:

    1. 写入前置标志位 0x4DM

    2. 写入 Map 的类型(字符串形式)

  2. 其次,遍历 Map.Entry,并将其序列化

    1. Value

  3. 最后,写入结束标志位 0x5AZ)。

HashMap 不同之处时,这里写入了 Map 的类型信息。所以,相比来说 HashMap 更加轻量级。在做微服务接口的参数和返回结果时,可以优先考虑 HashMap

再谈实例对象

为了方便叙述,在 Hessian 协议解释与实战(四):数组与集合:首谈实例对象 中,对对象的处理做了简要的概述。到这里,让我们再来认识一下实例对象。

处理实例对象的序列化主要有 JavaSerializerBeanSerializer。这两者的区别如下:

  • JavaSerializer 是通过反射获取实例对象的属性进行序列化。排除 statictransient 属性,对其他所有的属性进行递归序列化处理。

  • BeanSerializer 是遵循 POJI bean 的约定,扫描实例的所有方法,发现同时存在 Getter 和 Setter 方法的属性才进行序列化,它并不直接直接操作所有的属性。注意: BeanSerializer 将会无法处理 Getter 方法是以 is 开头的 boolean 属性,因为 BeanSerializer 只认以 get 开头的方法。

在 Java 8 中,其实默认使用的并不是这两个,而是 UnsafeSerializer。它与 JavaSerializer 相似,都是通过反射获取类的属性列表;但是与 JavaSerializer 不同之处时, JavaSerializer 通过 Field 使用反射获取实例对象属性对应的值;而 UnsafeSerializer 是使用 sun.misc.Unsafe 来获取字段的“指针”(offset),再通过“指针”获取实例对象属性对应的值。

另外,启用 UnsafeSerializer 的先决条件是能否获得 sun.misc.Unsafe 实例。如果可以获得 sun.misc.Unsafe 实例,则就会启用 UnsafeSerializer。当然,也可以通过配置 com.caucho.hessian.unsafe 变量为 false 来禁用 UnsafeSerializer。这里,还有一个例外:如果待序列化的类包含了 writeReplace() 方法,则就会启用 JavaSerializer

未完待续……

看在D瓜哥码字的辛苦上,请友情支持一下,D瓜哥感激不尽,😜

微信打赏码
支付宝打赏码

欢迎关注D瓜哥的微信公众号(更新巨慢,欢迎留言):

微信公众号
公众号的微信号是: jikerizhi因为众所周知的原因,有时图片加载不出来。如果图片加载不出来可以直接通过搜索微信号来查找D瓜哥的公众号。
来说两句吧...
我来说两句

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK