用netty 3的channelbuffer来重写序列化类

我们都知道用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文件的。

猜你喜欢

转载自my.oschina.net/u/3768341/blog/1817034