Netty源码分析-ProtobufEncoder-Decoder

Posted 征服.刘华强

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Netty源码分析-ProtobufEncoder-Decoder相关的知识,希望对你有一定的参考价值。

ProtobufEncoder源码分析

@Sharable
public class ProtobufEncoder extends MessageToMessageEncoder<MessageLiteOrBuilder> 
    @Override
    protected void encode(ChannelHandlerContext ctx, MessageLiteOrBuilder msg, List<Object> out)
            throws Exception 
        //当前对象如果是google protocol buffer生成的对象,他们都实现了该接口
        if (msg instanceof MessageLite) 
            //把byte[]包装了Bytebuf返回
            out.add(wrappedBuffer(((MessageLite) msg).toByteArray()));
            return;
        
        if (msg instanceof MessageLite.Builder) 
            out.add(wrappedBuffer(((MessageLite.Builder) msg).build().toByteArray()));
        
    

 

ProtobufDecoder源码分析

package io.netty.handler.codec.protobuf;

import com.google.protobuf.ExtensionRegistry;
import com.google.protobuf.ExtensionRegistryLite;
import com.google.protobuf.Message;
import com.google.protobuf.MessageLite;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.MessageToMessageDecoder;

import java.util.List;


@Sharable
public class ProtobufDecoder extends MessageToMessageDecoder<ByteBuf> 

    private static final boolean HAS_PARSER;

    static 
        boolean hasParser = false;
        try 
            // MessageLite.getParserForType() is not available until protobuf 2.5.0.
            MessageLite.class.getDeclaredMethod("getParserForType");
            hasParser = true;
         catch (Throwable t) 
            // Ignore
        

        HAS_PARSER = hasParser;
    

    private final MessageLite prototype;
    private final ExtensionRegistryLite extensionRegistry;

    /**
     * Creates a new instance.
     */
    public ProtobufDecoder(MessageLite prototype) 
        this(prototype, null);
    

    public ProtobufDecoder(MessageLite prototype, ExtensionRegistry extensionRegistry) 
        this(prototype, (ExtensionRegistryLite) extensionRegistry);
    

    public ProtobufDecoder(MessageLite prototype, ExtensionRegistryLite extensionRegistry) 
        if (prototype == null) 
            throw new NullPointerException("prototype");
        
        this.prototype = prototype.getDefaultInstanceForType();
        this.extensionRegistry = extensionRegistry;
    

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out)
            throws Exception 
        final byte[] array;
        final int offset;
        final int length = msg.readableBytes();
        //判断msg内部是否包含了byte数组
        if (msg.hasArray()) 
        	//直接去出byte数组
            array = msg.array();
            //offset是数组的起始位置,readerIndex是数组有效字节
            offset = msg.arrayOffset() + msg.readerIndex();
         else 
        	//创建一个length长度的数组
            array = new byte[length];
            //把底层字节写入数组
            msg.getBytes(msg.readerIndex(), array, 0, length);
            offset = 0;
        

        //根据protocol的API版本选择反序列化代码执行
        //将字节数组反序列化为protocol的实例
        if (extensionRegistry == null) 
            if (HAS_PARSER) 
                out.add(prototype.getParserForType().parseFrom(array, offset, length));
             else 
                out.add(prototype.newBuilderForType().mergeFrom(array, offset, length).build());
            
         else 
            if (HAS_PARSER) 
                out.add(prototype.getParserForType().parseFrom(
                        array, offset, length, extensionRegistry));
             else 
                out.add(prototype.newBuilderForType().mergeFrom(
                        array, offset, length, extensionRegistry).build());
            
        
    

 

编解码器应用,需要配合LengthFieldBasedFrameDecoder和LengthFieldPrepender,它俩使用定长4个字节写入消息长度。

 // Decoders
 pipeline.addLast("frameDecoder",
                  new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4));
 pipeline.addLast("protobufDecoder",
                  new ProtobufDecoder(MyMessage.getDefaultInstance()));

 // Encoder
 pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
 pipeline.addLast("protobufEncoder", new ProtobufEncoder());

还可以使用ProtobufVarint32FrameDecoder和ProtobufVarint32LengthFieldPrepender,它俩采用google的varint32编码包头长度字节。

ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
ch.pipeline().addLast(new ProtobufDecoder(RichManProto.RichMan.getDefaultInstance()));


ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
ch.pipeline().addLast(new ProtobufEncoder());

 

以上是关于Netty源码分析-ProtobufEncoder-Decoder的主要内容,如果未能解决你的问题,请参考以下文章

Netty源码分析(七) PoolChunk

源码分析Netty4专栏

源码分析Netty4专栏

netty之二次解码MessageToMessageDecoder

netty之二次解码MessageToMessageDecoder

netty之二次解码MessageToMessageDecoder