概念

序列化:将Java对象转化为字节数组

反序列化:将字节数组转化为Java对象

在RPC应用中,进行跨进程远程调用的时候,需要使用特定的序列化技术,需要对进行网络传输的对象进行序列化和反序列化。

影响序列化选择有两个因素

1. 序列化之后码流的大小,如果太大,那么将会影响网络传输的性能。

2.     序列化和反序列化过程的性能

常用的序列化框架性能比较

本文主要进行以下序列化框架的对比测试:

  • JDK
  • FastJson
  • Hessian
  • Protostuff

准备

需要序列化的对象,这是一个复杂的对象。

NettyMessage
public class NettyMessage  implements Serializable {

    //消息头
private Header header;
//消息体
private Object body;
} @Data
public class Header implements Serializable { //校验头
private int crcCode; //消息头消息体的总长度
private int length; //全局唯一id
private long sessionId; //消息类型
private MessageType type; //扩展字段
private Map<String,Object> attachment;
} @Data
public class RpcRequest implements Serializable {
private long requestId; //请求id
private String interfaceName; //调用类名
private String methodName; //调用方法名
private String[] parameterTypes; //方法参数类型
private Object[] parameters; //方法参数 }

创建一个构造器创建该对象。

public class NettyMessageBuilder {

    public  static NettyMessage build(){

        NettyMessage message = new NettyMessage();
Header header = new Header();
RpcRequest request = new RpcRequest(); header.setCrcCode(1234);
header.setType(MessageType.APP_RESPONE_TYPE);
header.setLength(100);
header.setSessionId(200); Map<String,Object> map = new LinkedHashMap<>(); map.put("demoKey",(Object)"demoValue");
header.setAttachment(map); request.setInterfaceName("com.demo");
String[] types = {"java.lang.String" ,"java.lang.Integer"};
String[] param = {"java.lang.String" ,"java.lang.Integer"};
request.setParameterTypes(types);
request.setParameters(param);
request.setMethodName("buy");
request.setRequestId(123456); message.setHeader(header);
message.setBody(request); return message;
} }

定义序列化接口

public abstract class AbstractSerialize {

    public  abstract   <T> byte[] serialize(T obj);
public abstract <T> T deserialize(byte[] data, Class<T> clazz); }

JDK

实现

public class JdkSerializeUtil extends AbstractSerialize {

    public <T> byte[] serialize(T obj) {

        if (obj  == null){
throw new NullPointerException();
} ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(obj);
return bos.toByteArray();
} catch (Exception ex) {
ex.printStackTrace();
}
return new byte[0];
} public <T> T deserialize(byte[] data, Class<T> clazz) {
ByteArrayInputStream bis = new ByteArrayInputStream(data); try {
ObjectInputStream ois = new ObjectInputStream(bis);
T obj = (T)ois.readObject();
return obj;
} catch (Exception ex) {
ex.printStackTrace();
} return null;
}
}

FastJson

引入pom

 <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>

实现

public class FastjsonSerializeUtil  extends AbstractSerialize {

    public <T> byte[] serialize(T obj) {
if (obj == null){
throw new NullPointerException();
} String json = JSON.toJSONString(obj);
byte[] data = json.getBytes();
return data;
} public <T> T deserialize(byte[] data, Class<T> clazz) { T obj = JSON.parseObject(new String(data),clazz);
return obj;
}
}

Hessian

<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.60</version>
</dependency>

实现

@Slf4j
public class HessianSerializeUtil extends AbstractSerialize { public <T> byte[] serialize(T obj) { if (obj == null){
throw new NullPointerException();
}
try{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
HessianOutput ho = new HessianOutput(bos);
ho.writeObject(obj); return bos.toByteArray();
}
catch(Exception ex){
log.error("HessianSerializeUtil序列化发生异常!"+ex);
throw new RuntimeException();
} } public <T> T deserialize(byte[] data, Class<T> clazz) { if (data == null){
throw new NullPointerException();
}
try{
ByteArrayInputStream bis = new ByteArrayInputStream(data);
HessianInput hi = new HessianInput(bis);
return (T)hi.readObject(); }
catch(Exception ex){
log.error("HessianSerializeUtil反序列化发生异常!"+ex);
throw new RuntimeException();
} }
}

Protostuff

<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.6.0</version>
<scope>compile</scope>
</dependency> <!-- https://mvnrepository.com/artifact/io.protostuff/protostuff-runtime -->
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.6.0</version>
</dependency>

实现

public class ProtostuffSerializeUtil  extends AbstractSerialize {

    /**
* 避免每次序列化都重新申请Buffer空间
*/
private static LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
/**
* 缓存Schema
*/
private static Map<Class<?>, Schema<?>> schemaCache = new ConcurrentHashMap<Class<?>, Schema<?>>(); public <T> byte[] serialize(T obj) { if (obj == null){
throw new NullPointerException();
}
Class<T> clazz = (Class<T>) obj.getClass();
Schema<T> schema = getSchema(clazz);
byte[] data;
try {
data = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
} finally {
buffer.clear();
} return data;
} public <T> T deserialize(byte[] data, Class<T> clazz) {
Schema<T> schema = getSchema(clazz);
T obj = schema.newMessage();
ProtostuffIOUtil.mergeFrom(data, obj, schema);
return obj;
} private static <T> Schema<T> getSchema(Class<T> clazz) {
Schema<T> schema = (Schema<T>) schemaCache.get(clazz);
if (schema == null) {
//这个schema通过RuntimeSchema进行懒创建并缓存
//所以可以一直调用RuntimeSchema.getSchema(),这个方法是线程安全的
schema = RuntimeSchema.getSchema(clazz);
if (schema != null) {
schemaCache.put(clazz, schema);
}
} return schema;
} }

测试

测试方法

 @Test
public void testFastJsonSerialize(){

     //这里替换各种序列化实现类
AbstractSerialize serialize = new ProtostuffSerializeUtil(); NettyMessage message = NettyMessageBuilder.build(); TimeUtil timeUtil = new TimeUtil();
TimeUtil timeUtil1 = new TimeUtil(); NettyMessage result = null;
byte[] serByte = serialize.serialize(message);
System.out.println("字节长度:" + serByte.length);
result = serialize.deserialize(serByte,NettyMessage.class);
     //这里设置测试次数
for(int i = 0; i< 100000; i++){
//timeUtil.init();
timeUtil.start();
serByte = serialize.serialize(message);
timeUtil.end();
//System.out.println("序列化时间:"+ timeUtil.getAvrTimeUs() + " Us"); timeUtil1.start();
result = serialize.deserialize(serByte,NettyMessage.class);
timeUtil1.end(); }
System.out.println("序列化时间:"+ timeUtil.getAvrTimeUs() + " Us");
System.out.println("反序列化时间:"+ timeUtil1.getAvrTimeUs() + " Us"); System.out.println("结果:" + result); }

这里定义了一个TimeUtil类来计时

public class TimeUtil {

    private  long startTime;
private long endTime;
private long timeSum;
private long count; public void init(){
timeSum = 0;
count = 0;
} public void start(){
startTime = System.nanoTime(); } public void end(){
endTime = System.nanoTime();
timeSum += (endTime-startTime);
count++;
} public long getAvrTimeNs(){
return (timeSum/count);
}
public long getAvrTimeUs(){
return (timeSum/count)/1000;
} public long getAvrTimeMs(){
return (timeSum/count)/1000000;
} }
  码流大小(byte) 10次(us) 100次(us) 1000次(us) 10000次(us) 100000次(us)  
FastJson 305 116-243 106-185 90-140 26-39 8-12  
JDK 866 383-777 502-1101 123-334 54-237 15-76  
Hessian 520 959-3836 376-567 191-329 99-161 30-47  
Protostuff 193 103-145 90-137 75-135 15-24 5-8  
               

注:

1. 码流单位为字节

2. 序列化耗时-反序列化耗时,单位为微秒

从以上测试可以看出

1. JDK方式的码流最大,不利于网络传输。

2. 从整体来看,Prorostuff的码流最小,序列化性能最好。

一些常用Java序列化框架的比较的更多相关文章

  1. [java]序列化框架性能对比(kryo、hessian、java、protostuff)

    序列化框架性能对比(kryo.hessian.java.protostuff) 简介:   优点 缺点 Kryo 速度快,序列化后体积小 跨语言支持较复杂 Hessian 默认支持跨语言 较慢 Pro ...

  2. Java序列化框架性能比較

    博客: http://colobu.com jvm-serializers提供了一个非常好的比較各种Java序列化的的測试套件. 它罗列了各种序列化框架. 能够自己主动生成測试报告. 我在AWS c3 ...

  3. java序列化框架(protobuf、thrift、kryo、fst、fastjson、Jackson、gson、hessian)性能对比

     我们为什么要序列化 举个栗子:下雨天我们要打伞,但是之后我们要把伞折叠起来,方便我们存放.那么运用到我们java中道理是一样的,我们要将数据分解成字节流,以便存储在文件中或在网络上传输,这叫序列 ...

  4. -1-3 java集合框架基础 java集合体系结构 Collection 常用java集合框架 如何选择集合 迭代器 泛型 通配符概念 Properties 集合 迭代器

    集合又称之为容器存储对象的一种方式 •数组虽然也可以存储对象,但长度是固定的:显然需要可变长度的容器 集合和数组的区别?                 A:长度区别                  ...

  5. Java集合框架(常用类) JCF

    Java集合框架(常用类) JCF 为了实现某一目的或功能而预先设计好一系列封装好的具有继承关系或实现关系类的接口: 集合的由来: 特点:元素类型可以不同,集合长度可变,空间不固定: 管理集合类和接口 ...

  6. Java程序员最常用的8个Java日志框架

    转自:http://www.codeceo.com/article/8-java-log-framework.html 作为一名Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用 ...

  7. 序列化框架性能对比(kryo、hessian、java、protostuff)

    简介:   优点 缺点 Kryo 速度快,序列化后体积小 跨语言支持较复杂 Hessian 默认支持跨语言 较慢 Protostuff 速度快,基于protobuf 需静态编译 Protostuff- ...

  8. 转:Java程序员最常用的8个Java日志框架

    作为一名Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用以及移动应用.然而日志系统是一个成熟Java应用所必不可少的,在开发和调试阶段,日志可以帮助我们更好更快地定位bug:在 ...

  9. 处理异常、常用类、反射、类加载与垃圾回收、java集合框架

    异常处理概述 检查异常:检查异常通常是用户错误或者不能被程序员所预见的问题.(cheched) 运行时异常:运行时异常是一个程序在运行过程中可能发生的.可以被程序员避免的异常类型.(Unchecked ...

随机推荐

  1. Linux时间子系统之三:时间的维护者:timekeeper

    专题文档汇总目录 Notes: 原文地址:Linux时间子系统之三:时间的维护者:timekeeper 本系列文章的前两节讨论了用于计时的时钟源:clocksource,以及内核内部时间的一些表示方法 ...

  2. ASP.NET Core & Docker 实战经验分享

    一.前言 最近一直在研究和实践ASP.NET Core.Docker.持续集成.在ASP.NET Core 和 Dcoker结合下遇到了一些坑,在此记录和分享,希望对大家有一些帮助. 二.中间镜像 我 ...

  3. DOS系统常用命令

    前言: DOS命令是DOS操作系统使用的命令.DOS操作系统是一种磁盘操作系统,从Windows95.98到今天的Windows10都内置有DOS操作系统.可以通过"win+R", ...

  4. 静态代码扫描工具PMD定制xml的规则(一)操作篇

    0.前言 PMD作为开源的静态代码扫描工具有很强的扩展能力,可使用java或xpath定制rule.第一篇从操作上讲解如何定制一个用于扫描xml是否规范的规则.首先我们知道xml格式的文件在java工 ...

  5. c# xml操作(二)

    c# xml操作(二) 此博文包含图片 (-- ::)转载▼ 标签: 杂谈 分类: c# 上次,我们介绍了增加和删除xml的一些操作,这次我们将介绍如何更改和读取xml特定节点.我们依然以上次的xml ...

  6. web项目部署到本地tomcat时,运行tomcat的startup.bat一闪而过

    在eclipse里面启动tomcat时都是正常的,打成War包后,也无法自动解压,百度了好多方法均尝试失败,然后看到了下方的百度经验,配完环境变量后,tomcat可以正常启动了.如下为步骤: 1. 遇 ...

  7. fileWriter.go

    package blog4go import ( "fmt" "path" "strings" ) // NewFileWriter ini ...

  8. BZOJ_1098_[POI2007]办公楼biu_链表优化BFS

    BZOJ_1098_[POI2007]办公楼biu_链表优化BFS Description FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的 电话号 ...

  9. BZOJ_1598_[Usaco2008 Mar]牛跑步_A*

    BZOJ_1598_[Usaco2008 Mar]牛跑步_A* Description BESSIE准备用从牛棚跑到池塘的方法来锻炼. 但是因为她懒,她只准备沿着下坡的路跑到池塘, 然后走回牛棚. B ...

  10. Mui Webview下来刷新上拉加载实现

    有些事情经历过之后才会发现,原来再次之前我是如此的啥,因为是第一次做,毫无头绪,有时会想假如有个一demo就好了,那么就不会花费这么多的无用功了.今天使用mui 的webview实现了一个H5页面的上 ...