我们都知道用java来序列化一个对象,需要用到ObjectOutputSteam来把对象写进一个字节流ByteOutputStream,然后把字节流转成字节数组。用ObjectInputSteam来反序列化,获取一个字节流,再读出对象。类似代码如下。
序列化类代码
package com.netty.java;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2018-05-22.
*/
public class Player implements Serializable{
private static final long serialVersionUID = -8914730421956537399L;
private long playerId;
private int age;
private String name;
private List<Integer> skills = new ArrayList<>();
public Player(long playerId,int age,String name) {
this.playerId = playerId;
this.age = age;
this.name = name;
}
public long getPlayerId() {
return playerId;
}
public void setPlayerId(long playerId) {
this.playerId = playerId;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Integer> getSkills() {
return skills;
}
public void setSkills(List<Integer> skills) {
this.skills = skills;
}
}
序列化和反序列化代码如下
package com.netty.java;
import java.io.*;
import java.util.Arrays;
/**
* Created by Administrator on 2018-05-22.
*/
public class Java2Bytes {
public static void main(String[] args) throws IOException, ClassNotFoundException {
byte[] bytes = toBytes();
toPlayer(bytes);
}
public static byte[] toBytes() throws IOException {
Player player = new Player(101,20,"天王乔嘉");
player.getSkills().add(1001);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(player);
byte[] byteArray = byteArrayOutputStream.toByteArray();
System.out.println(Arrays.toString(byteArray));
return byteArray;
}
public static void toPlayer(byte[] bs) throws IOException, ClassNotFoundException {
ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(bs));
Player player = (Player) inputStream.readObject();
System.out.println("PlayerId:" + player.getPlayerId() + " name:" + player.getName() + " age:" + player.getAge() + " skills:" + Arrays.toString(player.getSkills().toArray()));
}
}
运行后的结果为
[-84, -19, 0, 5, 115, 114, 0, 21, 99, 111, 109, 46, 110, 101, 116, 116, 121, 46, 106, 97, 118, 97, 46, 80, 108, 97, 121, 101, 114, -124, 72, -125, -23, -38, -23, -109, -55, 2, 0, 4, 73, 0, 3, 97, 103, 101, 74, 0, 8, 112, 108, 97, 121, 101, 114, 73, 100, 76, 0, 4, 110, 97, 109, 101, 116, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 76, 0, 6, 115, 107, 105, 108, 108, 115, 116, 0, 16, 76, 106, 97, 118, 97, 47, 117, 116, 105, 108, 47, 76, 105, 115, 116, 59, 120, 112, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 101, 116, 0, 12, -27, -92, -87, -25, -114, -117, -28, -71, -108, -27, -104, -119, 115, 114, 0, 19, 106, 97, 118, 97, 46, 117, 116, 105, 108, 46, 65, 114, 114, 97, 121, 76, 105, 115, 116, 120, -127, -46, 29, -103, -57, 97, -99, 3, 0, 1, 73, 0, 4, 115, 105, 122, 101, 120, 112, 0, 0, 0, 1, 119, 4, 0, 0, 0, 1, 115, 114, 0, 17, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 73, 110, 116, 101, 103, 101, 114, 18, -30, -96, -92, -9, -127, -121, 56, 2, 0, 1, 73, 0, 5, 118, 97, 108, 117, 101, 120, 114, 0, 16, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 78, 117, 109, 98, 101, 114, -122, -84, -107, 29, 11, -108, -32, -117, 2, 0, 0, 120, 112, 0, 0, 3, -23, 120] PlayerId:101 name:天王乔嘉 age:20 skills:[1001]
现在用netty 3 channelbuffer来重写这个过程,我们需要一个序列化的抽象类以及buffer工厂
package com.netty.serializer;
import org.jboss.netty.buffer.ChannelBuffer;
import java.nio.charset.Charset;
import java.util.*;
/**
* Created by Administrator on 2018-05-21.
*/
public abstract class Serializer {
public static final Charset CHARSET = Charset.forName("UTF-8");
protected ChannelBuffer writeBuffer;
protected ChannelBuffer readBuffer;
protected abstract void read();
protected abstract void write();
public Serializer readFromBytes(byte[] bytes) {
readBuffer = BufferFactory.getBuffer(bytes);
read();
readBuffer.clear();
return this;
}
public void readFromBuffer(ChannelBuffer readBuffer) {
this.readBuffer = readBuffer;
read();
}
public ChannelBuffer writeToLocalBuff() {
writeBuffer = BufferFactory.getBuffer();
write();
return writeBuffer;
}
public ChannelBuffer writeToTargetBuff(ChannelBuffer buffer) {
writeBuffer = buffer;
write();
return writeBuffer;
}
public byte[] getBytes() {
writeToLocalBuff();
byte[] bytes = null;
if (writeBuffer.writerIndex() == 0) {
bytes = new byte[0];
}else {
bytes = new byte[writeBuffer.writerIndex()];
writeBuffer.readBytes(bytes);
}
writeBuffer.clear();
return bytes;
}
public byte readByte() {
return readBuffer.readByte();
}
public short readShort() {
return readBuffer.readShort();
}
public int readInt() {
return readBuffer.readInt();
}
public long readLong() {
return readBuffer.readLong();
}
public float readFloat() {
return readBuffer.readFloat();
}
public double readDouble() {
return readBuffer.readDouble();
}
@SuppressWarnings("Since15")
public String readString() {
int size = readBuffer.readShort();
if (size <= 0) {
return "";
}
byte[] bytes = new byte[size];
readBuffer.readBytes(bytes);
return new String(bytes, CHARSET);
}
public <T> List<T> readList(Class<T> clz) {
List<T> list = new ArrayList<T>();
int size = readBuffer.readShort();
for (int i = 0;i < size;i++) {
list.add(read(clz));
}
return list;
}
public <K,V> Map<K,V> readMap(Class<K> keyClz,Class<V> valueClz) {
Map<K,V> map = new HashMap<K, V>();
int size = readBuffer.readShort();
for (int i = 0;i < size;i++) {
K key = read(keyClz);
V value = read(valueClz);
map.put(key,value);
}
return map;
}
public <I> I read(Class<I> clz) {
Object t = null;
if (clz == int.class || clz == Integer.class) {
t = this.readInt();
}else if (clz == byte.class || clz == Byte.class) {
t = this.readByte();
}else if (clz == short.class || clz == Short.class) {
t = this.readShort();
}else if (clz == long.class || clz == Long.class) {
t = this.readLong();
}else if (clz == float.class || clz == Float.class) {
t = this.readFloat();
}else if (clz == double.class || clz == Double.class) {
t = this.readDouble();
}else if (clz == String.class) {
t = this.readString();
}else if (Serializer.class.isAssignableFrom(clz)) {
try {
byte hasObject = this.readBuffer.readByte();
if (hasObject == 1) {
Serializer team = (Serializer)clz.newInstance();
team.readFromBuffer(this.readBuffer);
t = team;
}else {
t = null;
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}else {
throw new RuntimeException(String.format("不支持类型:[%s]",clz));
}
return (I)t;
}
public Serializer writeByte(Byte value) {
writeBuffer.writeByte(value);
return this;
}
public Serializer writeShort(Short value) {
writeBuffer.writeShort(value);
return this;
}
public Serializer writeInt(Integer value) {
writeBuffer.writeInt(value);
return this;
}
public Serializer writeLong(Long value) {
writeBuffer.writeLong(value);
return this;
}
public Serializer writeFloat(Float value) {
writeBuffer.writeFloat(value);
return this;
}
public Serializer writeDouble(Double value) {
writeBuffer.writeDouble(value);
return this;
}
public <T> Serializer writeList(List<T> list) {
if (isEmpty(list)) {
writeBuffer.writeShort((short)0);
return this;
}
writeBuffer.writeShort((short)list.size());
for (T item:list) {
writeObject(item);
}
return this;
}
public <K,V> Serializer writeMap(Map<K,V> map) {
if (isEmpty(map)) {
writeBuffer.writeShort((short)0);
return this;
}
writeBuffer.writeShort((short)map.size());
for (Map.Entry<K,V> entry:map.entrySet()) {
writeObject(entry.getKey());
writeObject(entry.getValue());
}
return this;
}
@SuppressWarnings("Since15")
public Serializer writeString(String value) {
if (value == null || value.isEmpty()) {
writeShort((short)0);
return this;
}
byte[] data = value.getBytes(CHARSET);
short len = (short)data.length;
writeBuffer.writeShort(len);
writeBuffer.writeBytes(data);
return this;
}
public Serializer writeObject(Object object) {
if (object == null) {
writeByte((byte)0);
}else {
if (object instanceof Integer) {
writeInt((Integer)object);
return this;
}
if (object instanceof Long) {
writeLong((Long)object);
return this;
}
if (object instanceof Short) {
writeShort((Short)object);
return this;
}
if (object instanceof Byte) {
writeByte((Byte)object);
return this;
}
if (object instanceof String) {
String value = (String)object;
writeString(value);
return this;
}
if (object instanceof Serializer) {
writeByte((byte)1);
Serializer value = (Serializer)object;
value.writeToTargetBuff(writeBuffer);
return this;
}
throw new RuntimeException("不可序列化的类型:" + object.getClass());
}
return this;
}
private <T> boolean isEmpty(Collection<T> c) {
return c == null || c.size() == 0;
}
private <K,V> boolean isEmpty(Map<K,V> c) {
return c == null || c.size() == 0;
}
}
package com.netty.serializer;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import java.nio.ByteOrder;
/**
* Created by Administrator on 2018-05-21.
*/
public class BufferFactory {
public static ByteOrder BYTE_ORDER = ByteOrder.BIG_ENDIAN;
public static ChannelBuffer getBuffer() {
ChannelBuffer dynamicBuffer = ChannelBuffers.dynamicBuffer();
return dynamicBuffer;
}
public static ChannelBuffer getBuffer(byte[] bytes) {
ChannelBuffer copiedBuffer = ChannelBuffers.copiedBuffer(bytes);
return copiedBuffer;
}
}
我们要序列化的实体类要继承该抽象类,并实现各自的抽象方法。
package com.netty.serializer;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2018-05-22.
*/
public class Player extends Serializer {
private int id;
private String name;
private int age;
private List<Integer> skills = new ArrayList<>();
public List<Integer> getSkills() {
return skills;
}
public void setSkills(List<Integer> skills) {
this.skills = skills;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
protected void read() {
this.id = readInt();
this.name = readString();
this.age = readInt();
this.skills = readList(Integer.class);
}
@Override
protected void write() {
writeInt(id);
writeString(name);
writeInt(age);
writeList(skills);
}
}
序列化和反序列化主类
package com.netty.serializer;
import java.util.Arrays;
/**
* Created by Administrator on 2018-05-22.
*/
public class Test {
public static void main(String[] args) {
Player player = new Player();
player.setId(101);
player.setName("天王乔嘉");
player.setAge(45);
player.getSkills().add(1001);
byte[] bytes = player.getBytes();
System.out.println(Arrays.toString(bytes));
Player player1 = new Player();
player1.readFromBytes(bytes);
System.out.println(player1.getId() + " " + player1.getName() + " " + player1.getAge() +" " + Arrays.toString(player1.getSkills().toArray()));
}
}
运行的结果为
[0, 0, 0, 101, 0, 12, -27, -92, -87, -25, -114, -117, -28, -71, -108, -27, -104, -119, 0, 0, 0, 45, 0, 1, 0, 0, 3, -23] 101 天王乔嘉 45 [1001]
对比结果发现序列化的长度,后者比前者小很多。
当然最小的序列化还是google的protoBuffer,这个是要自己去定义protobuffer的*.proto文件的。