java 序列化框架_一些常用Java序列化框架的比较

概念

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

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

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

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

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

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

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

5059ef372f9cb413af1efed27b9d4aee.png

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

JDK

FastJson

Hessian

Protostuff

准备

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

NettyMessage

public class NettyMessage implementsSerializable {//消息头

privateHeader header;//消息体

privateObject body;

}

@Datapublic class Header implementsSerializable {//校验头

private intcrcCode;//消息头消息体的总长度

private intlength;//全局唯一id

private longsessionId;//消息类型

privateMessageType type;//扩展字段

private Mapattachment;

}

@Datapublic class RpcRequest implementsSerializable {private long requestId; //请求id

private String interfaceName; //调用类名

private String methodName; //调用方法名

private String[] parameterTypes; //方法参数类型

private Object[] parameters; //方法参数

}

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

public classNettyMessageBuilder {public staticNettyMessage build(){

NettyMessage message= newNettyMessage();

Header header= newHeader();

RpcRequest request= newRpcRequest();

header.setCrcCode(1234);

header.setType(MessageType.APP_RESPONE_TYPE);

header.setLength(100);

header.setSessionId(200);

Map 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);returnmessage;

}

}

定义序列化接口

public abstract classAbstractSerialize {public abstract byte[] serialize(T obj);public abstract T deserialize(byte[] data, Classclazz);

}

JDK

实现

public class JdkSerializeUtil extendsAbstractSerialize {public byte[] serialize(T obj) {if (obj == null){throw newNullPointerException();

}

ByteArrayOutputStream bos= newByteArrayOutputStream();try{

ObjectOutputStream oos= newObjectOutputStream(bos);

oos.writeObject(obj);returnbos.toByteArray();

}catch(Exception ex) {

ex.printStackTrace();

}return new byte[0];

}public T deserialize(byte[] data, Classclazz) {

ByteArrayInputStream bis= newByteArrayInputStream(data);try{

ObjectInputStream ois= newObjectInputStream(bis);

T obj=(T)ois.readObject();returnobj;

}catch(Exception ex) {

ex.printStackTrace();

}return null;

}

}

FastJson

引入pom

com.alibaba

fastjson

1.2.56

实现

public class FastjsonSerializeUtil extendsAbstractSerialize {public byte[] serialize(T obj) {if (obj == null){throw newNullPointerException();

}

String json=JSON.toJSONString(obj);byte[] data =json.getBytes();returndata;

}public T deserialize(byte[] data, Classclazz) {

T obj= JSON.parseObject(newString(data),clazz);returnobj;

}

}

Hessian

com.caucho

hessian

4.0.60

实现

@Slf4jpublic class HessianSerializeUtil extendsAbstractSerialize {public byte[] serialize(T obj) {if (obj == null){throw newNullPointerException();

}try{

ByteArrayOutputStream bos= newByteArrayOutputStream();

HessianOutput ho= newHessianOutput(bos);

ho.writeObject(obj);returnbos.toByteArray();

}catch(Exception ex){

log.error("HessianSerializeUtil序列化发生异常!"+ex);throw newRuntimeException();

}

}public T deserialize(byte[] data, Classclazz) {if (data == null){throw newNullPointerException();

}try{

ByteArrayInputStream bis= newByteArrayInputStream(data);

HessianInput hi= newHessianInput(bis);return(T)hi.readObject();

}catch(Exception ex){

log.error("HessianSerializeUtil反序列化发生异常!"+ex);throw newRuntimeException();

}

}

}

Protostuff

io.protostuff

protostuff-core

1.6.0

compile

io.protostuff

protostuff-runtime

1.6.0

实现

public class ProtostuffSerializeUtil extendsAbstractSerialize {/*** 避免每次序列化都重新申请Buffer空间*/

private static LinkedBuffer buffer =LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);/*** 缓存Schema*/

private static Map, Schema>> schemaCache = new ConcurrentHashMap, Schema>>();public byte[] serialize(T obj) {if (obj == null){throw newNullPointerException();

}

Class clazz = (Class) obj.getClass();

Schema schema =getSchema(clazz);byte[] data;try{

data=ProtostuffIOUtil.toByteArray(obj, schema, buffer);

}finally{

buffer.clear();

}returndata;

}public T deserialize(byte[] data, Classclazz) {

Schema schema =getSchema(clazz);

T obj=schema.newMessage();

ProtostuffIOUtil.mergeFrom(data, obj, schema);returnobj;

}private static Schema getSchema(Classclazz) {

Schema schema = (Schema) schemaCache.get(clazz);if (schema == null) {//这个schema通过RuntimeSchema进行懒创建并缓存//所以可以一直调用RuntimeSchema.getSchema(),这个方法是线程安全的

schema =RuntimeSchema.getSchema(clazz);if (schema != null) {

schemaCache.put(clazz, schema);

}

}returnschema;

}

}

测试

测试方法

@Testpublic voidtestFastJsonSerialize(){

//这里替换各种序列化实现类

AbstractSerialize serialize= newProtostuffSerializeUtil();

NettyMessage message=NettyMessageBuilder.build();

TimeUtil timeUtil= newTimeUtil();

TimeUtil timeUtil1= newTimeUtil();

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 classTimeUtil {private longstartTime;private longendTime;private longtimeSum;private longcount;public voidinit(){

timeSum= 0;

count= 0;

}public voidstart(){

startTime=System.nanoTime();

}public voidend(){

endTime=System.nanoTime();

timeSum+= (endTime-startTime);

count++;

}public longgetAvrTimeNs(){return (timeSum/count);

}public longgetAvrTimeUs(){return (timeSum/count)/1000;

}public longgetAvrTimeMs(){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的码流最小,序列化性能最好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值