我们都知道用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 Listskills = 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 getSkills() { return skills; } public void setSkills(List 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); } publicList readList(Class clz) { List list = new ArrayList (); int size = readBuffer.readShort(); for (int i = 0;i < size;i++) { list.add(read(clz)); } return list; } public Map readMap(Class keyClz,Class valueClz) { Map map = new HashMap (); 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 read(Class 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 Serializer writeList(List list) { if (isEmpty(list)) { writeBuffer.writeShort((short)0); return this; } writeBuffer.writeShort((short)list.size()); for (T item:list) { writeObject(item); } return this; } public Serializer writeMap(Map map) { if (isEmpty(map)) { writeBuffer.writeShort((short)0); return this; } writeBuffer.writeShort((short)map.size()); for (Map.Entry 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 boolean isEmpty(Collection c) { return c == null || c.size() == 0; } private boolean isEmpty(Map 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 Listskills = new ArrayList<>(); public List getSkills() { return skills; } public void setSkills(List 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文件的。