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接口
  2. ExtSerializerFactory extSerializerFactory = new ExtSerializerFactory();
    extSerializerFactory.addSerializer(class , mySerializer); //添加自定义的序列化接口
    extSerializerFactory.addDeserializer(class , myDeserializer); //添加自定义的反序列化接口
    
    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之后就解决了.

测试代码


    public static void exceptionTest() throws Exception {
        Exception exception = null;
        try {
            FileInputStream stream = new FileInputStream("notfound");
        } catch (FileNotFoundException e) {
            exception = e;
        }

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        HessianOutput out = new HessianOutput(bos);
        out.writeObject(exception);
        out.flush();

        byte[] bytes = bos.toByteArray();
        ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
        HessianInput in = new HessianInput(bin);
        Exception read = (Exception) in.readObject(FileNotFoundException.class);
        read.printStackTrace();
        System.out.println(read);
    }
 
hessian支持对流进行压缩处理,可以看下 Deflation
Hessian2Output out = new Hessian2Output(bos);
out = envelope.wrap(out); //包装为压缩

Hessian2Input in = new Hessian2Input(bin);
in = envelope.unwrap(in); //解缩
 
压缩慎用,在测试过程中有一些磕磕碰碰的小问题。 

后记

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

 

序列化数据对比


bytes字节数对比


具体的数字: 

 protobufjacksonxstreamSerializablehessian2hessian2压缩hessian1
序列化(单位ns)11545421 92406 101892679410076629027
反序列化(单位ns)13348743 117329 640273787118843237596
bytes97311 664 824374283495

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值