`

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. Java代码 复制代码 收藏代码
    1. ExtSerializerFactory extSerializerFactory = new ExtSerializerFactory();   
    2. extSerializerFactory.addSerializer(class , mySerializer); //添加自定义的序列化接口   
    3. extSerializerFactory.addDeserializer(class , myDeserializer); //添加自定义的反序列化接口   
    4.   
    5. serializerFactory.addFactory(extSerializerFactory); //注册ext到序列化工厂  
    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之后就解决了.
 

测试代码

 
Java代码 复制代码 收藏代码
  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. }  
    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
Java代码 复制代码 收藏代码
  1. Hessian2Output out = new Hessian2Output(bos);   
  2. out = envelope.wrap(out); //包装为压缩   
  3.   
  4. Hessian2Input in = new Hessian2Input(bin);   
  5. in = envelope.unwrap(in); //解缩  
Hessian2Output out = new Hessian2Output(bos);
out = envelope.wrap(out); //包装为压缩

Hessian2Input in = new Hessian2Input(bin);
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

 

 

分享到:
评论

相关推荐

    hessian学习基础篇——序列化和反序列化

    例如,服务器端可以使用Hessian序列化响应数据,客户端则通过反序列化接收到的二进制流来获取对象。这使得通信过程更为高效,尤其在数据量较大时,相比于文本格式,二进制格式能显著减少网络传输时间。 Hessian工具...

    Hessian 的字段序列化小记

    - 首先,Hessian序列化器会遍历Java对象的所有字段,对每个字段进行处理。 - 对于基本类型,如int、boolean、double等,Hessian有专门的编码方式,直接将其转换为字节。 - 对于复杂类型如对象和数组,Hessian会...

    hessian最新源码分析.pdf

    总结一下,Hessian的源码分析主要关注客户端的`HessianProxy`和服务器端的`HessianSkeleton`这两个核心类。它们分别负责客户端的调用代理和服务器端的请求处理。源码中包含了方法名缓存、特殊方法的本地处理、以及...

    Hessian

    **五、源码分析** 对于深入理解Hessian的工作机制,阅读和分析源码是必不可少的。Caucho Technology提供了Hessian的开源实现,开发者可以通过阅读源码了解其内部细节,如序列化和反序列化的具体实现、类型转换逻辑...

    Hessian 学习 例子 实例

    服务端使用Hessian序列化`Person`对象,客户端则接收这个二进制流并反序列化为`Person`对象。这可以通过Hessian提供的库来实现,例如在Java中,我们可以使用Caucho的Hessian库。 在实际应用中,Hessian常用于微服务...

    hessian-4.0.51-src

    三、源码分析 1. **序列化与反序列化**:在"**src**"目录下,可以看到"**com.caucho.hessian.io**"包,其中包含了Hessian的序列化和反序列化实现。例如,`Hessian2Input`和`Hessian2Output`类分别用于反序列化和...

    hessian php与java通讯demo源码

    Hessian库会自动处理序列化和反序列化,使得客户端可以像调用本地方法一样调用远程服务。 3. **PHP客户端** (`php-client.rar`): - PHP客户端同样利用Hessian协议来调用Java服务器上的服务。 - PHP中,你可以...

    Spring中集成Hessian的问题

    Hessian的源码分析可以帮助我们更深入地理解其工作原理。Hessian服务端的序列化和反序列化过程、HTTP请求处理以及异常处理等都是关键部分。而Spring框架如何与Hessian进行集成,包括服务注册、请求处理和代理创建等...

    hessian-4.0.7.jar + src

    1. 理解Hessian序列化和反序列化的机制,包括基本类型和自定义类型的处理。 2. 学习如何在Java项目中配置和使用Hessian客户端和服务端。 3. 掌握如何通过Hessian源码调试和优化性能。 4. 熟悉Hessian与其他通信协议...

    hessian

    在这个过程中,开发者需要注意的是,虽然Hessian协议提供了自动类型映射,但有时仍需自定义序列化和反序列化的逻辑,特别是在处理自定义对象或者特殊数据结构时。 在实际应用中,Hessian常用于构建轻量级的分布式...

    hessian4.0.7结合spring2.5.6的bug

    2. **序列化/反序列化问题**:Hessian基于二进制序列化,如果Spring中的bean或者数据模型在序列化过程中出现问题,可能导致服务调用失败或者数据解析错误。例如,自定义类型的序列化没有正确实现,或者某些字段在反...

    Hessian 入门介绍

    1. **二进制格式**: Hessian使用二进制格式进行数据序列化和反序列化,与XML或JSON等文本格式相比,其数据体积更小,解析速度更快。 2. **RPC协议**: Hessian基于HTTP协议,提供了一种轻量级的远程调用方式,使得...

    自己写了个Hessian

    1. **序列化和反序列化**:Hessian协议的核心在于将Java对象转换成二进制流(序列化)和从二进制流恢复对象(反序列化)。这需要对Java的反射API有深入的理解,以便获取和设置对象的字段值。 2. **类型编码**:...

    Hessian源代码

    1. **源码文件**:包含了Hessian的核心实现,包括序列化和反序列化的算法,以及与其他网络协议的接口。 2. **示例代码**:这些示例可以帮助我们理解如何在实际项目中使用Hessian,包括创建服务端、客户端,以及调用...

    spring整合hessian进行远程通讯

    3. **使用源码分析**: Hessian库提供了`HessianProxyFactoryBean`和`HessianServiceExporter`这两个关键类。前者用于客户端创建Hessian服务的代理,后者在服务端用于导出Hessian服务。通过阅读这些类的源码,我们...

    闲着没事Hessian开发WebService的总结(一)

    读者可能能从中了解到如何集成Hessian到他们的项目中,以及如何通过源码分析来调试和优化Hessian服务。 从压缩包子文件的文件名称“BurlapWS”来看,这可能是与Burlap相关的,Burlap是Hessian的一个变种,也是一个...

    dubbo源码分析pdf.zip

    书中详细解析了Netty、HTTP、TCP等通信机制,以及Hessian和Protobuf等序列化方式,让读者能够理解服务间的通信过程。 3. **RPC实现**:RPC(Remote Procedure Call)是Dubbo的核心,书中详细讲解了从服务调用到结果...

    Hessian加密传输

    Hessian是一种二进制RPC(远程过程调用)协议,它提供了简洁高效的序列化方式,常用于服务之间的通信。在传输过程中,为了保护数据不被非法获取或篡改,通常会对数据进行加密,这就是所谓的“Hessian加密传输”。 ...

    Hessian入门案例源代码

    5. **Hessian序列化和反序列化**: Hessian协议负责将Java对象转换为二进制流在网络上传输,然后在另一端反序列化回原来的对象。这个过程是透明的,开发者无需关心具体细节。 6. **性能优势**: Hessian使用二...

Global site tag (gtag.js) - Google Analytics