- 背景
最近在处理一个hessian的反序列化问题时,因为服务端使用了pojo bean中多了一个enum属性,导致客户端在反序列化时疯狂的在打印日志。警告说找不到对应的enum class,因为项目中本身是设置了log4j的根输出为一个文件。
比较奇怪的是,hessian对应的日志输出全都打印到了控制台(虽然我们对console进行了重定向输出),导致对应的文件达到几百MB。无奈之下,仔细分析了下hessian的源码。
介绍
先看一张hessian主要的几个概念图
说明:
- Serializer 序列化的接口
- Deserializer 反序列化的接口
- AbstractHessianInput hessian自定义的输入流,提供对应的read各种类型的方法
- AbstractHessianOutput hessian自定义的输出流,提供对应的write各种类型的方法
AbstractSerializerFactory介绍
serializerFactory从字面意思上也看的出来,是管理和维护对应序列化/反序列化机制的工厂。默认的几种实现
- SerializerFactory 标准的实现
- ExtSerializerFactory 我们可以设置自定义的序列化机制,通过该Factory可以进行扩展。
- BeanSerializerFactory 对SerializerFactory的默认object的序列化机制进行强制指定,指定为BeanSerializer。 具体BeanSerializer的实现后面再表。
自定义序列化机制的扩展:
- 实现Serializer/Deserializer接口
-
- ExtSerializerFactory extSerializerFactory = new ExtSerializerFactory();
- extSerializerFactory.addSerializer(class , mySerializer); //添加自定义的序列化接口
- extSerializerFactory.addDeserializer(class , myDeserializer); //添加自定义的反序列化接口
- 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之后就解决了.
测试代码
- 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);
- }
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); //解缩
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序列化器会遍历Java对象的所有字段,对每个字段进行处理。 - 对于基本类型,如int、boolean、double等,Hessian有专门的编码方式,直接将其转换为字节。 - 对于复杂类型如对象和数组,Hessian会...
总结一下,Hessian的源码分析主要关注客户端的`HessianProxy`和服务器端的`HessianSkeleton`这两个核心类。它们分别负责客户端的调用代理和服务器端的请求处理。源码中包含了方法名缓存、特殊方法的本地处理、以及...
**五、源码分析** 对于深入理解Hessian的工作机制,阅读和分析源码是必不可少的。Caucho Technology提供了Hessian的开源实现,开发者可以通过阅读源码了解其内部细节,如序列化和反序列化的具体实现、类型转换逻辑...
服务端使用Hessian序列化`Person`对象,客户端则接收这个二进制流并反序列化为`Person`对象。这可以通过Hessian提供的库来实现,例如在Java中,我们可以使用Caucho的Hessian库。 在实际应用中,Hessian常用于微服务...
三、源码分析 1. **序列化与反序列化**:在"**src**"目录下,可以看到"**com.caucho.hessian.io**"包,其中包含了Hessian的序列化和反序列化实现。例如,`Hessian2Input`和`Hessian2Output`类分别用于反序列化和...
Hessian库会自动处理序列化和反序列化,使得客户端可以像调用本地方法一样调用远程服务。 3. **PHP客户端** (`php-client.rar`): - PHP客户端同样利用Hessian协议来调用Java服务器上的服务。 - PHP中,你可以...
Hessian的源码分析可以帮助我们更深入地理解其工作原理。Hessian服务端的序列化和反序列化过程、HTTP请求处理以及异常处理等都是关键部分。而Spring框架如何与Hessian进行集成,包括服务注册、请求处理和代理创建等...
1. 理解Hessian序列化和反序列化的机制,包括基本类型和自定义类型的处理。 2. 学习如何在Java项目中配置和使用Hessian客户端和服务端。 3. 掌握如何通过Hessian源码调试和优化性能。 4. 熟悉Hessian与其他通信协议...
在这个过程中,开发者需要注意的是,虽然Hessian协议提供了自动类型映射,但有时仍需自定义序列化和反序列化的逻辑,特别是在处理自定义对象或者特殊数据结构时。 在实际应用中,Hessian常用于构建轻量级的分布式...
2. **序列化/反序列化问题**:Hessian基于二进制序列化,如果Spring中的bean或者数据模型在序列化过程中出现问题,可能导致服务调用失败或者数据解析错误。例如,自定义类型的序列化没有正确实现,或者某些字段在反...
1. **二进制格式**: Hessian使用二进制格式进行数据序列化和反序列化,与XML或JSON等文本格式相比,其数据体积更小,解析速度更快。 2. **RPC协议**: Hessian基于HTTP协议,提供了一种轻量级的远程调用方式,使得...
1. **序列化和反序列化**:Hessian协议的核心在于将Java对象转换成二进制流(序列化)和从二进制流恢复对象(反序列化)。这需要对Java的反射API有深入的理解,以便获取和设置对象的字段值。 2. **类型编码**:...
1. **源码文件**:包含了Hessian的核心实现,包括序列化和反序列化的算法,以及与其他网络协议的接口。 2. **示例代码**:这些示例可以帮助我们理解如何在实际项目中使用Hessian,包括创建服务端、客户端,以及调用...
3. **使用源码分析**: Hessian库提供了`HessianProxyFactoryBean`和`HessianServiceExporter`这两个关键类。前者用于客户端创建Hessian服务的代理,后者在服务端用于导出Hessian服务。通过阅读这些类的源码,我们...
读者可能能从中了解到如何集成Hessian到他们的项目中,以及如何通过源码分析来调试和优化Hessian服务。 从压缩包子文件的文件名称“BurlapWS”来看,这可能是与Burlap相关的,Burlap是Hessian的一个变种,也是一个...
书中详细解析了Netty、HTTP、TCP等通信机制,以及Hessian和Protobuf等序列化方式,让读者能够理解服务间的通信过程。 3. **RPC实现**:RPC(Remote Procedure Call)是Dubbo的核心,书中详细讲解了从服务调用到结果...
Hessian是一种二进制RPC(远程过程调用)协议,它提供了简洁高效的序列化方式,常用于服务之间的通信。在传输过程中,为了保护数据不被非法获取或篡改,通常会对数据进行加密,这就是所谓的“Hessian加密传输”。 ...
5. **Hessian序列化和反序列化**: Hessian协议负责将Java对象转换为二进制流在网络上传输,然后在另一端反序列化回原来的对象。这个过程是透明的,开发者无需关心具体细节。 6. **性能优势**: Hessian使用二...