Netty(六)之protostuff

protostuff和protobuf的區別

  • protostuff是一個基於protobuf實現的序列化方法
  • 在幾乎不損耗性能的情況下做到了不用我們寫.proto文件來實現序列化
  • 使用它也非常簡單,所以直接上代碼。

操作流程

前提

Netty(一)之helloworld   https://blog.csdn.net/qq_37171353/article/details/100180406   

的基礎之上修改

pom

<dependency>
            <groupId>org.objenesis</groupId>
            <artifactId>objenesis</artifactId>
            <version>2.6</version>
        </dependency>

        <dependency>
            <groupId>com.dyuproject.protostuff</groupId>
            <artifactId>protostuff-api</artifactId>
            <version>1.0.10</version>
        </dependency>
        <dependency>
            <groupId>com.dyuproject.protostuff</groupId>
            <artifactId>protostuff-core</artifactId>
            <version>1.0.10</version>
        </dependency>
        <dependency>
            <groupId>com.dyuproject.protostuff</groupId>
            <artifactId>protostuff-runtime</artifactId>
            <version>1.0.10</version>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>5.0.0.Alpha1</version>
        </dependency>

創建自定義的POJO

public class MsgInfo {

    private Integer id;
    private String msg;

//getter setter  構造方法省略。。。
}

創建序列化工具類、編解碼類

我看了很多博客,寫的大體都差不多這個樣子,這裏不需要要改動

ObjSerializationUtil
package protostuff;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author CBeann
 * @create 2019-09-24 20:01
 */
public class ObjSerializationUtil {

    private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<>();

    private static Objenesis objenesis = new ObjenesisStd();

    private ObjSerializationUtil() {

    }

    /**
     * 序列化(對象 -> 字節數組)
     *
     * @param obj 對象
     * @return 字節數組
     */
    public static <T> byte[] serialize(T obj) {
        Class<T> cls = (Class<T>) obj.getClass();
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        try {
            Schema<T> schema = getSchema(cls);
            return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        } finally {
            buffer.clear();
        }
    }

    /**
     * 反序列化(字節數組 -> 對象)
     *
     * @param data
     * @param cls
     * @param <T>
     */
    public static <T> T deserialize(byte[] data, Class<T> cls) {
        try {
            T message = objenesis.newInstance(cls);
            Schema<T> schema = getSchema(cls);
            ProtostuffIOUtil.mergeFrom(data, message, schema);
            return message;
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

    private static <T> Schema<T> getSchema(Class<T> cls) {
        Schema<T> schema = (Schema<T>) cachedSchema.get(cls);
        if (schema == null) {
            schema = RuntimeSchema.createFrom(cls);
            cachedSchema.put(cls, schema);
        }
        return schema;
    }

}
ObjDecoder
package protostuff;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * @author CBeann
 * @create 2019-09-24 19:53
 */
public class ObjDecoder extends ByteToMessageDecoder {



    private Class<?> genericClass;

    public ObjDecoder(Class<?> genericClass) {
        this.genericClass = genericClass;
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        if (in.readableBytes() < 4) {
            return;
        }
        in.markReaderIndex();
        int dataLength = in.readInt();
        if (in.readableBytes() < dataLength) {
            in.resetReaderIndex();
            return;
        }
        byte[] data = new byte[dataLength];
        in.readBytes(data);
        out.add(ObjSerializationUtil.deserialize(data, genericClass));
    }

}
ObjEncoder
package protostuff;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

/**
 * @author CBeann
 * @create 2019-09-24 20:03
 */
public class ObjEncoder  extends MessageToByteEncoder {

    private Class<?> genericClass;

    public ObjEncoder(Class<?> genericClass) {
        this.genericClass = genericClass;
    }

    @Override
    protected void encode(ChannelHandlerContext ctx, Object in, ByteBuf out)  {
        if (genericClass.isInstance(in)) {
            byte[] data = ObjSerializationUtil.serialize(in);
            out.writeInt(data.length);
            out.writeBytes(data);
        }
    }

}

 

修改TimeServer和TimeClient

修改的一樣

//對象傳輸處理
socketChannel.pipeline().addLast(new ObjDecoder(MsgInfo.class));
socketChannel.pipeline().addLast(new ObjEncoder(MsgInfo.class));

修改TimeClient發送POJO

 //發送數據
            MsgInfo msgInfo =
                    new MsgInfo(1, "客戶端:--->" + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
            f.channel().writeAndFlush(msgInfo);
            Thread.sleep(4000);
            msgInfo = new MsgInfo(1, "客戶端:--->" + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
            f.channel().writeAndFlush(msgInfo);

修改TimeServerHandler

 @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        //服務器讀客戶端發送來的數據
        MsgInfo msgInfo = (MsgInfo) msg;
        System.out.println("The TimeServer receive :" + msgInfo);

        //服務器向客戶端迴應請求
        msgInfo = new MsgInfo(2, "服務端:--->" + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
        ctx.writeAndFlush(msgInfo);


    }

修改TimeClientHandler

    //客戶端讀取服務器發送的數據
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            //服務器讀客戶端發送來的數據
            MsgInfo msgInfo = (MsgInfo) msg;
            System.out.println("客戶端收到 :   " + msg);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //標配
            ReferenceCountUtil.release(msg);
        }
    }

測試

項目代碼下載

鏈接:https://pan.baidu.com/s/1gmbNwmAb3gEZX-c1XvYdQQ 
提取碼:w7w1 
複製這段內容後打開百度網盤手機App,操作更方便哦

參考

https://mp.weixin.qq.com/s?__biz=MzIxMDAwMDAxMw==&mid=2650724806&idx=1&sn=bb986119b9cdd950e2e6d995295e7f06&scene=19#wechat_redirect

https://blog.csdn.net/qq_18860653/article/details/77649229

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章