目录
测试条件
序列化对象
结果展示
码流大小比较
fastJson < kryo < hessian < jdk
序列化+反序列化速度
测试代码
序列化+反序列化
序列化速度
反序列化速度
待验证
四种序列化介绍以及Demo
JDK自带序列化
Hessian
Hessian2.0的Demo实现
Kryo
为什么kryo序列化后的字节流很小?
FastJson
序列化框架版本
序列化框架 | fastjson | kryo | hessian | jdk |
版本 | 1.2.29 | 3.0.3 | 4.0.62 | 1.8 |
采用同一个对象 RpcInvocation 进行测试,由于 bean 对象的不同,测试结果可能会有差异。
static final String UUIDstr = UUID.randomUUID().toString();
static RpcInvocation rpcInvocation = new RpcInvocation();
static {
rpcInvocation.setRetry(1);
rpcInvocation.setTargetMethod("sendData");
rpcInvocation.setTargetServiceName("org.idea.VVrpc.framework.interfaces.DataService");
rpcInvocation.setArgs(new Object[]{"hello"});
rpcInvocation.setUuid(UUIDstr);
}
@BenchmarkMode({Mode.Throughput})
@Warmup(iterations = 3,time = 3,timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 3, time = 5,timeUnit = TimeUnit.SECONDS)
@Fork(1)
public class SerializeRpcCompareTest {
static final String UUIDstr = UUID.randomUUID().toString();
static RpcInvocation rpcInvocation = new RpcInvocation();
static {
rpcInvocation.setRetry(1);
rpcInvocation.setTargetMethod("sendData");
rpcInvocation.setTargetServiceName("org.idea.VVrpc.framework.interfaces.DataService");
rpcInvocation.setArgs(new Object[]{"hello"});
rpcInvocation.setUuid(UUIDstr);
}
static SerializeFactory jdkserializeFactory = new JdkSerializeFactory();
static SerializeFactory hesserializeFactory = new HessianSerializeFactory();
static SerializeFactory fastserializeFactory = new FastJsonSerializeFactory();
static SerializeFactory kryoserializeFactory = new KryoSerializeFactory();
@Benchmark
public void jdkSerializeTest(){
byte[] result = jdkserializeFactory.serialize(rpcInvocation);
RpcInvocation deserializeUser = jdkserializeFactory.deserialize(result,RpcInvocation.class);
}
@Benchmark
public void hessianSerializeTest(){
byte[] result = hesserializeFactory.serialize(rpcInvocation);
RpcInvocation deserializeUser = hesserializeFactory.deserialize(result,RpcInvocation.class);
}
@Benchmark
public void fastJsonSerializeTest(){
byte[] result = fastserializeFactory.serialize(rpcInvocation);
RpcInvocation deserializeUser = fastserializeFactory.deserialize(result,RpcInvocation.class);
}
@Benchmark
public void kryoSerializeTest(){
byte[] result = kryoserializeFactory.serialize(rpcInvocation);
RpcInvocation deserializeUser = kryoserializeFactory.deserialize(result,RpcInvocation.class);
}
public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder()
.include(SerializeRpcCompareTest.class.getSimpleName())
.build();
new Runner(options).run();
}
}
Score 表示 每秒进行 score次操作 单位: ops: operations per second
一次操作指的是 执行一次方法体内的程序。
fastjson > kryo > hessian >> jdk
网上的测试 kryo大都排在第一位,可能测试的代码或者场景有些问题。
搜到的一些可能原因:
1.kryo 针对每一种类型 在序列化反序列化前都要实例化,否则会异常
但是实例化又会影响性能,所以使用时,针对特定类型只要实例化一次,速度就会飞快.
2.kryo在复杂对象的序列化时效果会比较好。
JDK自带的序列化框架使用_trigger333的博客-CSDN博客
深入理解Java序列化机制:ObjectOutputStream源码简要分析_A__Plus的博客-CSDN博客_objectoutputstream
Hessian是caucho公司开发的轻量级RPC(Remote Procedure Call)框架,它使用HTTP协议传输,使用Hessian二进制序列化。
Hessian由于其支持跨语言、高效的二进制序列化协议,被经常用于序列化框架使用。Hessian序列化协议分为Hessian1.0和Hessian2.0,Hessian2.0协议对序列化过程进行了优化(优化内容待看),在性能上相较Hessian1.0有明显提升。
public class HessianSerializeFactory implements SerializeFactory {
@Override
public byte[] serialize(T t) {
byte[] data = null;
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
Hessian2Output output = new Hessian2Output(os);
output.writeObject(t);
output.getBytesOutputStream().flush();
output.completeMessage();
output.close();
data = os.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
}
return data;
}
@Override
public T deserialize(byte[] data, Class clazz) {
if (data == null) {
return null;
}
Object result = null;
try {
ByteArrayInputStream is = new ByteArrayInputStream(data);
Hessian2Input input = new Hessian2Input(is);
result = input.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
return (T) result;
}
Kryo一个快速有效的Java二进制序列化框架,它依赖底层ASM库用于字节码生成,因此有比较好的运行速度。Kryo的目标就是提供一个序列化速度快、结果体积小、API简单易用的序列化框架。Kryo支持自动深/浅拷贝,它是直接通过对象->对象的深度拷贝,而不是对象->字节->对象的过程。
kryo不是线程安全的, 所以需要使用ThreadLocal来存储kryo对象
比kyro更高效的序列化库就只有google的protobuf了(而且两者性能很接近),protobuf有个缺点就是要传输的每一个类的结构都要生成对应的proto文件(也可以都放在同一个proto文件中,如果考虑到扩展性的话,不建议放在一个proto文件中),如果某个类发生修改,还得重新生成该类对应的proto文件.
源码分析Dubbo序列化-源码分析kryo序列化实现原理 - 码农岛
Kryo 对 Class 的序列化只需要化 Class 的全路径名,在反序列化时根据 Class 通过类加载进行加载,大大减少了序列化后的文件大小,能极大提高性能。
Kryo 的核心设计理念就是尽最大可能减少序列化后的文件大小,其举措1就是通过对long,int等数据类型,采用变长字节存储来代替java中使用固定字节(4,8)字节的模式,因为在软件开发中,对象的这些值基本上都是小值,能节省很多空间,第二个举措是使用了类似缓存的机制,在一次序列化对象中,在整个递归序列化期间,相同的对象,只会序列化一次,后续的用一个局部int值来代替。
public class KryoSerializeFactory implements SerializeFactory {
private static final ThreadLocal kryos = new ThreadLocal() {
@Override
protected Kryo initialValue() {
Kryo kryo = new Kryo();
return kryo;
}
};
@Override
public byte[] serialize(T t) {
Output output = null;
try {
// 从当前线程中的 ThreadLocalMap 中拿到 kryo 并写入字节流
Kryo kryo = kryos.get();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
output = new Output(byteArrayOutputStream);
kryo.writeClassAndObject(output, t);
return output.toBytes();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (output != null) {
output.close();
}
}
}
@Override
public T deserialize(byte[] data, Class clazz) {
Input input = null;
try {
// 从当前线程中的 ThreadLocalMap 中拿到 kryo 并将字节流转化为 对象
Kryo kryo = kryos.get();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);
input = new Input(byteArrayInputStream);
return (T) kryo.readClassAndObject(input);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (input != null) {
input.close();
}
}
}
}
fastjson详解_吴声子夜歌的博客-CSDN博客_fastjson
在前后端数据传输交互中,经常会遇到字符串(String)与json,XML等格式相互转换与解析,其中json以跨语言,跨前后端的优点在开发中被频繁使用,基本上可以说是标准的数据交换格式。fastjson 是一个java语言编写的高性能且功能完善的JSON库,它采用一种“假定有序快速匹配”的算法,把JSON Parse 的性能提升到了极致。它的接口简单易用,已经被广泛使用在缓存序列化,协议交互,Web输出等各种应用场景中。
Demo 把 json 字符串转为 byte数组即可。
public class FastJsonSerializeFactory implements SerializeFactory {
@Override
public byte[] serialize(T t) {
String jsonStr = JSON.toJSONString(t);
return jsonStr.getBytes();
}
@Override
public T deserialize(byte[] data, Class clazz) {
return JSON.parseObject(new String(data),clazz);
}
}
转换效果:
参考:
几种常用序列化框架_涛歌依旧fly的博客-CSDN博客_序列化框架
jackson、fastjson、kryo、protostuff等序列化工具性能对比_双面神像的博客-CSDN博客_kryo和fastjson