赞
踩
序列化:将Java对象转化为字节数组
反序列化:将字节数组转化为Java对象
在RPC应用中,进行跨进程远程调用的时候,需要使用特定的序列化技术,需要对进行网络传输的对象进行序列化和反序列化。
影响序列化选择有两个因素:
常用的序列化框架性能比较
需要序列化的对象,这是一个复杂的对象。
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 enum MessageType { APP_RESPONE_TYPE; }
创建一个构造器创建该对象。
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);
}
实现
import lombok.SneakyThrows; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class JdkSerializeUtil extends AbstractSerialize { @SneakyThrows public <T> byte[] serialize(T obj) { if (obj == null) { throw new NullPointerException(); } ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(obj); return bos.toByteArray(); } @SneakyThrows public <T> T deserialize(byte[] data, Class<T> clazz) { ByteArrayInputStream bis = new ByteArrayInputStream(data); ObjectInputStream ois = new ObjectInputStream(bis); T obj = (T) ois.readObject(); return obj; } }
引入pom
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>
实现
import com.alibaba.fastjson.JSON; 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; } }
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.60</version>
</dependency>
实现
import com.caucho.hessian.io.HessianInput; import com.caucho.hessian.io.HessianOutput; import lombok.SneakyThrows; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; public class HessianSerializeUtil extends AbstractSerialize { @SneakyThrows public <T> byte[] serialize(T obj) { if (obj == null){ throw new NullPointerException(); } ByteArrayOutputStream bos = new ByteArrayOutputStream(); HessianOutput ho = new HessianOutput(bos); ho.writeObject(obj); return bos.toByteArray(); } @SneakyThrows public <T> T deserialize(byte[] data, Class<T> clazz) { if (data == null){ throw new NullPointerException(); } ByteArrayInputStream bis = new ByteArrayInputStream(data); HessianInput hi = new HessianInput(bis); return (T)hi.readObject(); } }
实现:
import com.caucho.hessian.io.Hessian2Input; import com.caucho.hessian.io.Hessian2Output; import lombok.SneakyThrows; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; public class Hessian2SerializeUtil extends AbstractSerialize { @SneakyThrows public <T> byte[] serialize(T obj) { if (obj == null){ throw new NullPointerException(); } ByteArrayOutputStream bos = new ByteArrayOutputStream(); Hessian2Output ho = new Hessian2Output(bos); ho.writeObject(obj); ho.flush(); return bos.toByteArray(); } @SneakyThrows public <T> T deserialize(byte[] data, Class<T> clazz) { if (data == null){ throw new NullPointerException(); } ByteArrayInputStream bis = new ByteArrayInputStream(data); Hessian2Input hi = new Hessian2Input(bis); return (T)hi.readObject(); } }
<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; } }
测试方法
import com.lot.entity.NettyMessage; import com.lot.entity.NettyMessageBuilder; import com.lot.serialize.AbstractSerialize; import com.lot.serialize.FastjsonSerializeUtil; import com.lot.serialize.HessianSerializeUtil; import com.lot.serialize.JdkSerializeUtil; import com.lot.serialize.ProtostuffSerializeUtil; public class Main { public static void main(String[] args) { //这里替换各种序列化实现类 // AbstractSerialize serialize = new JdkSerializeUtil(); // AbstractSerialize serialize = new FastjsonSerializeUtil(); // AbstractSerialize serialize = new HessianSerializeUtil(); 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 |
Hessian2 | 398 | 132-152 | 142-144 | 33-35 | 12-13 | 6-6 |
Protostuff | 193 | 103-145 | 90-137 | 75-135 | 15-24 | 5-8 |
注:
从以上测试可以看出
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。