之前分析了序列化一个对象的流程,基本上可以归纳成先获取一个对象的序列化类,然后由该序列化类来序列化对象;那么究竟有哪些序列化类,以及这些类是如何序列化的就是我们本次分析的重点(参考源码版本3.0.13)!
先看下整个序列化类的的类图:
可以看出:
1.它们都是AbstractSerializer的子类;
2.实现序列化的方法是:void writeObject(Object obj, AbstractHessianOutput out)方法;
现在我们就分别讨论这些类的实现,首先是
BasicSerializer类(用来序列化java基本类型,以及基本类型数组)
Integer obj = new Integer(10);
// 这里得到的就是:BasicSerializer(理由请看上一篇分析)
serializer = _serializerFactory.getSerializer(obj.getClass());
serializer.writeObject(obj, this);
现在我们看下BasicSerializer的writeObject方法:
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException
{
switch (code) {
// 针对每一种类型,做出相应的序列化
case BOOLEAN:
// 省略后面代码...
default:
throw new RuntimeException(code + " " + String.valueOf(obj.getClass()));
}
}
1.现在我们详细的看一下每一种类型如何序列化,首先看下boolean/Boolean
case BOOLEAN:
out.writeBoolean(((Boolean) obj).booleanValue());
break;
writeBoolean方法的实现还是比较简单的,
如果是true就输出'T',否则输出'F'
public void writeBoolean(boolean value)
throws IOException
{
if (value)
os.write('T');
else
os.write('F');
}
我们看下例子:
out.writeObject(true);
2.序列化 byte, short, int(包括相应的对象类型):
case BYTE:
case SHORT:
case INTEGER:
out.writeInt(((Number) obj).intValue());
break;
发现没,对于byte, short都是当做int来序列化!
writeInt的输出格式为:
‘I’ b32 b24 b16 b8 (b32代表从第32位开始的8位, b24代表从第24位开始的8位,后面以此类推)
public void writeInt(int value)
throws IOException
{
os.write('I');
os.write(value >> 24);
os.write(value >> 16);
os.write(value >> 8);
os.write(value);
}
我们看一个例子:
int intValue = 1234;
out.writeObject(intValue);
short shortVale = 300;
out.writeObject(shortVale);
3.序列化long(包括相应的对象类型)
case LONG:
out.writeLong(((Number) obj).longValue());
break;
writeLong的输出格式为:
'L' b64 b56 b48 b40 b32 b24 b16 b8
public void writeLong(long value)
throws IOException
{
os.write('L');
os.write((byte) (value >> 56));
os.write((byte) (value >> 48));
os.write((byte) (value >> 40));
os.write((byte) (value >> 32));
os.write((byte) (value >> 24));
os.write((byte) (value >> 16));
os.write((byte) (value >> 8));
os.write((byte) (value));
}
4.序列化float, double(包括相应的对象类型)
case FLOAT:
case DOUBLE:
out.writeDouble(((Number) obj).doubleValue());
break;
从这里我们也可以看出,float也是当做double类型序列化
另外writeDouble的输出格式为:
'D' b64 b56 b48 b40 b32 b24 b16 b8
public void writeDouble(double value)
throws IOException
{
long bits = Double.doubleToLongBits(value);
os.write('D');
os.write((byte) (bits >> 56));
os.write((byte) (bits >> 48));
os.write((byte) (bits >> 40));
os.write((byte) (bits >> 32));
os.write((byte) (bits >> 24));
os.write((byte) (bits >> 16));
os.write((byte) (bits >> 8));
os.write((byte) (bits));
}
我汇总long,double来看一个例子:
long longValue = 1234567L;
double doubleValue = 1.2345D;
out.writeObject(longValue);
out.writeObject(doubleValue);
5.字符char和字符串String的序列化
case CHARACTER:
out.writeString(String.valueOf(obj));
break;
case STRING:
out.writeString((String) obj);
break;
可以看到char和String都是使用writeString方法进行序列化,序列化格式为:
'S' 字符串长度 字符串每个字符的值
public void writeString(String value)
throws IOException
{
if (value == null) {
os.write('N');
}
else {
int length = value.length();
int offset = 0;
// 这里一段while循环我暂时没有深究,大概是对超长字符串的输出处理
while (length > 0x8000) {
int sublen = 0x8000;
char tail = value.charAt(offset + sublen - 1);
if (0xd800 <= tail && tail <= 0xdbff)
sublen--;
os.write('s');
os.write(sublen >> 8);
os.write(sublen);
printString(value, offset, sublen);
length -= sublen;
offset += sublen;
}
// 输出:'S' 字符串长度
os.write('S');
os.write(length >> 8);
os.write(length);
// 输出:字符串中每个字符的值
printString(value, offset, length);
}
}
我们还是看一个例子比较直观:
String strValue = "Hello Hessian!";
out.writeObject(strValue);
上面我们基本已经讲了基本类型和相应的对象类型序列化,现在我们来看下相应的数组类型的序列化;
数组序列化格式比较简单,基本上可以归纳为
:'Vt' 长度 '[数组类型' 'l' 数组长度 数组元素... 'z'
我们仅以long型数组为例:
case LONG_ARRAY:
{
// 关于这个ref目前可以忽略,后面的文章会说明
if (out.addRef(obj))
return;
long []data = (long []) obj;
// 输出数组格式头:'Vt' 长度5 '[long' 'l' 数组长度
out.writeListBegin(data.length, "[long");
for (int i = 0; i < data.length; i++)
// 输出数组中每一个元素(看看这里是不是很熟悉?对,就是我们刚才分析的那些)
out.writeLong(data[i]);
// 输出结束标记: 'z'
out.writeListEnd();
break;
}
我们具体看下writeListBegin 和 writeListEnd的实现
public boolean writeListBegin(int length, String type)
throws IOException
{
os.write('V');
if (type != null) {
os.write('t');
printLenString(type);
}
if (length >= 0) {
os.write('l');
os.write(length >> 24);
os.write(length >> 16);
os.write(length >> 8);
os.write(length);
}
return true;
}
public void writeListEnd()
throws IOException
{
os.write('z');
}
话不多说,上代码
long[] arrayLong = new long[] { 12345L, 1234L, 789L };
out.writeObject(arrayLong);
关于序列化基本类型数组,
还有两点需要注意:
1.序列化short类型数组,虽然type标记是[short,但是其中的每一个元素还是当做int来序列化,同理对于float型数组,标记为[float,但是对于每一个元素时当做double来序列化;
2.byte类型数组的序列化比较特殊,他基本当成了一个String来输出,只是开始标记为'B'
总结
1.BasicSerializer可以序列化哪些类型?(主要是java基本类型,基本类型数组(包括相应的对象类型);
2.对于每一种的序列化格式是什么?
最后我自己制作了一个表格,大致叙说了各个类型的序列化格式:
- 大小: 12.7 KB
- 大小: 120.8 KB
- 大小: 14 KB
- 大小: 18.4 KB
- 大小: 16.4 KB
- 大小: 24.6 KB
- 大小: 24.6 KB
- 大小: 47.7 KB
- 大小: 83.1 KB
分享到:
相关推荐
公司搞soa治理,正好采用hessian的export暴露接口,我修改了下,客户端不需要采用url,直接采用servicename,从zookeeper取地址列表。客户端和服务端通过mina通讯,不采用原生的http协议。目前mina的编码解码还有待...
《Hessian源码分析与Hack:携带远程调用端信息》 Hessian作为一种轻量级的RPC(远程过程调用)框架,因其高效、简洁的二进制协议,被广泛应用于构建Web服务。然而,在实际应用中,有时我们需要获取到远程调用端的IP...
这个压缩包包含了Hessian的多个版本,分别是Hessian3.1.6、Hessian3.2.1以及Hessian4.0.7。每个版本都有其特定的功能改进和优化,了解这些版本的区别和适用场景对于开发者来说至关重要。 Hessian3.1.6是Hessian的一...
在深入分析Hessian的源码之前,我们先来理解一下Hessian是什么。Hessian是一种二进制的Remoting协议,它允许Java应用通过HTTP进行高效、简洁的数据交换。Hessian客户端和服务端之间的通信基于HTTP协议,实现了远程...
这个"**Hessian源码示例**"很可能包含了使用HessianCSharp库在C#环境中实现服务端和客户端通信的示例代码。HessianCSharp是.NET平台上的一个开源库,它实现了Hessian协议,使得开发者可以方便地在.NET应用程序之间...
通过阅读和分析Hessian的源码,我们可以了解其如何编码和解码各种数据类型,以及如何优化序列化和反序列化的过程。这对于优化自定义序列化逻辑或者解决Hessian使用中遇到的问题非常有帮助。 总结起来,Hessian是一...
至于标签"源码",学习Hessian时查看源码有助于理解其内部工作原理,比如数据如何被编码和解码。你可以通过阅读开源的Hessian库,如Caucho Hessian的Java实现,来了解其底层细节。 至于"工具",有一些工具可以帮助...
hessian源码
四、Hessian的优点 Hessian具有以下优点: * 高性能:Hessian基于Binary-RPC协议实现,具有高性能和低延迟。 * 轻量级:Hessian是轻量级的RPC解决方案,易于使用和部署。 * 跨语言支持:Hessian支持多种编程语言,...
hessian-3.2.0源码,在做分布式交互时,可能要重写hessian
在android与web端实现hessian通信,源码为android客户端源码,jar包来自http://hsrong.iteye.com/blog/1719996,google官网提供的hessdroid不可用,因为里面包含一些android不支持的类;hessian官网的jar包适用于web...
源码也使得开发者能够根据需要修改或扩展Hessian的功能,例如添加新的序列化策略,或者优化特定场景下的性能。 Hessian在实际应用中,通常被用来构建RPC(Remote Procedure Call)框架,使得服务端的方法可以直接在...
对于深入理解Hessian的工作机制,阅读和分析源码是必不可少的。Caucho Technology提供了Hessian的开源实现,开发者可以通过阅读源码了解其内部细节,如序列化和反序列化的具体实现、类型转换逻辑等。 在博客链接...
Hessian是一种二进制协议,它被设计用于提高远程调用的...通过学习和实践这个Hessian demo,你将能够更好地应对涉及远程调用和数据交换的问题。无论是Java开发者还是C++开发者,Hessian都是值得了解和掌握的一项技术。
### Nacos JRaft Hessian 反序列化 RCE 分析 #### 一、背景介绍 Nacos 是阿里巴巴开源的一款易于构建云原生应用的动态服务发现、配置管理和服务管理平台。JRafT 是 SOFAStack 微服务平台中的一个分布式一致性组件...
这是一个Hessian入门学习的实例,程序包是一个web工程,使用intellij idea + Maven开发,其中通过两个方式展示了使用Hessian实现RMI的原理,一个是访问jsp页面,一个是在代码中手工创建client。对于Hessian Servlet...
通过计算图像每个像素位置的Hessian矩阵,我们可以分析其特征,例如检测图像中的血管、纹理或结构性边缘。 多尺度是指在不同分辨率下应用Hessian滤波器,这样可以更好地适应图像中的各种尺度特征。在小尺度上,...
在这个“hessian学习实例”中,我们将深入探讨Hessian框架的使用,特别是如何将其与Spring框架集成,以及如何构建server端和client端。 首先,让我们理解Hessian的工作原理。Hessian基于HTTP协议,它将Java对象序列...
总之,这个"PHP与Java通信Demo源码"是一个很好的学习资源,帮助开发者理解如何在PHP和Java之间使用Hessian协议进行通信。通过分析和实践这些示例代码,你可以更好地掌握Hessian的工作原理和使用方式,为你的跨语言...
在示例代码中,我们将通过 Hessian protocol 调用这四个方法,并截取并分析请求报文和应答报文的格式。 2.1 Hessian 报文结构应用示例背景说明 在示例代码中,我们使用 Java 语言编写了一个简单的示例,用于形象地...