实现自己的序列化协议

首先,我们知道序列化就是将对象变成字节数组,以便传输,而反序列化就是将字节数组变为原来的对象,这里我们借助Netty中的channelBuffer 来实现 ,其实channelBuffer可以理解为能动态扩容的Bytebuffe,能够自动扩容,这就好比数组与arrayList之间的关系,感兴趣的可以参照利用数组实现ArrayList的方式来实现自己的动态Bytebuffer,在这里不是重点,就不实现了

首先让我们来看一个简单的例子序列化例子

package com.lin.Serial;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;

import java.util.Arrays;

/**
 * @author zoujianglin
 * @date 2018/7/29 17:53
 */
public class Test1 {

    public static void main(String[] args){
        int id =5;
        int age = 21;
        ChannelBuffer channelBuffer =  ChannelBuffers.dynamicBuffer() ;
        channelBuffer.writeInt(id);
        channelBuffer.writeInt(age);
        int index =channelBuffer.writerIndex();//写了多少字节 类似于bytebuffer中的position
        byte[] bytes= new byte[index];
        channelBuffer.readBytes(bytes); //将其中的字节读入到bytes中
        System.out.println(Arrays.toString(bytes));
        // ================================================
         ChannelBuffer channelBuffer1 = ChannelBuffers.copiedBuffer(bytes); //创建一个含有bytes内容的ChannelBuffer
         int id1= channelBuffer1.readInt();
         int age1= channelBuffer1.readInt();

        System.out.println("id:"+ id1+" "+"age1:"+age1);



    }


}

上面就是我们自定义序列化的基本原理 ,总结起来就是将属性按照一定的顺序读入,在按照一定的顺序读出 看明白的上面的代码 接下来的话看起来就比较轻松了  首先我们定义一个buffer工厂用来获取channelbuffer

package com.lin.Serial;


import java.nio.ByteOrder;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
/**
 * @author zoujianglin
 * @date 2018/7/29 18:07
 */
public class BufferFactory {
   
   public static ByteOrder BYTE_ORDER = ByteOrder.BIG_ENDIAN;

   /**
    * 获取一个buffer
    * 
    * @return
    */
   public static ChannelBuffer getBuffer() {
      ChannelBuffer dynamicBuffer = ChannelBuffers.dynamicBuffer();
      return dynamicBuffer;
   }

   /**
    * 将数据写入buffer
    * @param bytes
    * @return
    */
   public static ChannelBuffer getBuffer(byte[] bytes) {
      ChannelBuffer copiedBuffer = ChannelBuffers.copiedBuffer(bytes);
      return copiedBuffer;
   }

}

接下啦就是要实现我们自己的序列化框架了,其中比较麻烦的是对象的集合和map等属性,对象属性,其代码逻辑有点长但都比较简单 ,耐心看的话还是比较容易看懂的

package com.lin.Serial;

import org.jboss.netty.buffer.ChannelBuffer;

import java.nio.charset.Charset;
import java.util.*;
import java.util.Map.Entry;

/**
 * @author zoujianglin
 * @date 2018/7/29 18:23
 */
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();

    /**
     * 从byte数组获取数据
     *
     * @param bytes 读取的数组
     */
    public Serializer readFromBytes(byte[] bytes) {
        readBuffer = BufferFactory.getBuffer(bytes);
        read();
        readBuffer.clear();
        return this;
    }

    /**
     * 从buff获取数据
     *
     * @param readBuffer
     */
    public void readFromBuffer(ChannelBuffer readBuffer) {
        this.readBuffer = readBuffer;
        read();
    }

    /**
     * 写入本地buff
     *
     * @return
     */
    public ChannelBuffer writeToLocalBuff() {
        writeBuffer = BufferFactory.getBuffer();
        write();
        return writeBuffer;
    }

    /**
     * 写入目标buff
     *
     * @param buffer
     * @return
     */
    public ChannelBuffer writeToTargetBuff(ChannelBuffer buffer) {
        writeBuffer = buffer;
        write(); //调用对象自身的序列化方法 需要自己覆盖
        return writeBuffer;
    }

    /**
     * 返回buffer数组
     *
     * @return
     */
    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();
    }

    public String readString() {
        int size = readBuffer.readShort();
        if (size <= 0) {
            return "";
        }

        byte[] bytes = new byte[size];
        readBuffer.readBytes(bytes);
        try {
            return new String(bytes, "UTF-8");

        } catch (Exception e) {
            throw new RuntimeException("字符编码错误");
        }

    }

    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;
    }

    @SuppressWarnings("unchecked")
    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 = readFloat();
        } else if (clz == double.class || clz == Double.class) {
            t = readDouble();
        } else if (clz == String.class) {
            t = readString();
        } else if (Serializer.class.isAssignableFrom(clz)) {
            try {
                byte hasObject = this.readBuffer.readByte();
                if (hasObject == 1) {
                    Serializer temp = (Serializer) clz.newInstance();
                    temp.readFromBuffer(this.readBuffer);
                    t = temp;
                } else {
                    t = null;
                }
            } catch (Exception 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()); //先写入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()); //先写入map的size()
        for (Entry<K, V> entry : map.entrySet()) {
            writeObject(entry.getKey());
            writeObject(entry.getValue());
        }
        return this;
    }

    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;
    }

    public <K, V> boolean isEmpty(Map<K, V> c) {
        return c == null || c.size() == 0;
    }
}

到这里就完成了 接下来我们就来测试一下
package com.lin.Serial;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;

import java.util.Arrays;

/**
 * @author zoujianglin
 * @date 2018/7/29 17:53
 */
public class Test1 extends Serializer {

    private static int age;
    private static int id;

    public Test1(int age, int id) {
        this.id = id;
        this.age = age;
    }

    public Test1() {
    }

    public static void main(String[] args) {
        Test1 test1 = new Test1(12, 23);
        byte[] bytes= test1.getBytes(); //序列化 字节数组
        Test1 test2 = new Test1();
        test2.readFromBytes(bytes); 反序列化
        System.out.println(test2.id+" "+test2.age);
    }


    @Override
    protected void read() {
        //注意读入和写入的顺序要一致
        this.age = this.readInt();
        this.id = this.readInt();
    }

    @Override
    protected void write() {
        int t= this.age;
        this.writeInt(this.age);
        this.writeInt(this.id);
    }
}

发现反序列化后对象属性一致,到此就完成了 !!!!

猜你喜欢

转载自blog.csdn.net/qq_32459653/article/details/81274704
今日推荐