1 ByteToMessageDecoder.java类的基本结构如下:



 



netty源码解析之netty解码器_java

 



其中ByteToMessageDecoder类是累加器的基础类,其核心方法如下:


// ByteToMessageDecoder.java
  
 
  
@Override
 
  
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
 
  
    if (msg instanceof ByteBuf) {
 
  
        // 首先会从RECYCLE的stack中取一个对象 return RECYCLER.get();
 
  
        CodecOutputList out = CodecOutputList.newInstance();
 
  
        try {
 
  
            ByteBuf data = (ByteBuf) msg;
 
  
            first = cumulation == null;
 
  
            // 判断是否第一次读,第一次读直接赋值
 
  
            if (first) {
 
  
                cumulation = data;
 
  
            } else {
 
  
                // A点: 非第一次进行字节流的累加
 
  
                cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data);
 
  
            }
 
  
            // B点:对累加的字节流进行解析,并解析到out中(B点会提供一个decode(ctx, in, out);给子类进行实现 --模板方法模式)
 
  
            callDecode(ctx, cumulation, out);
 
  
        } catch (DecoderException e) {
 
  
            throw e;
 
  
        } catch (Throwable t) {
 
  
            throw new DecoderException(t);
 
  
        } finally {
 
  
            if (cumulation != null && !cumulation.isReadable()) {
 
  
                numReads = 0;
 
  
                cumulation.release();
 
  
                cumulation = null;
 
  
           } else if (++ numReads >= discardAfterReads) {
 
  
                // We did enough reads already try to discard some bytes so we not risk to see a OOME.
 
  
                // See https://github.com/netty/netty/issues/4275
 
  
                numReads = 0;
 
  
                discardSomeReadBytes();
 
  
            }
 
  

    
  
 
  
            int size = out.size();
 
  
            decodeWasNull = !out.insertSinceRecycled();
 
  
            // C点:将字节流byteBuf向下传播
 
  

               fireChannelRead(ctx, out, size);
 
  
            out.recycle();
 
  
        }
 
  
    } else {
 
  
        ctx.fireChannelRead(msg);
 
  
    }
 
  
}
 
  

    
  
 
  

   首先分析上面A点:非第一次进行字节流的累加 ,跟踪源码如下:
  
 
  
• private Cumulator cumulator = MERGE_CUMULATOR;
• 继续跟踪源码如下:
// ByteToMessageDecoder.java
 
  
public static final Cumulator MERGE_CUMULATOR = new Cumulator() {
 
  
    @Override
 
  
    public ByteBuf cumulate(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf in) {
 
  
        ByteBuf buffer;
 
  
        // 判断当前是否还有空间可写
 
  
        if (cumulation.writerIndex() > cumulation.maxCapacity() - in.readableBytes() || cumulation.refCnt() > 1) {
 
  
            // 如果有就进行拓展
 
  
            buffer = expandCumulation(alloc, cumulation, in.readableBytes());
 
  
        } else {
 
  
            buffer = cumulation;
 
  
        }
 
  
        // 将新来的字节流加入到buf中,然后释放
 
  
        buffer.writeBytes(in);
 
  
        in.release();
 
  
        return buffer;
 
  
    }
 
  
};
 
  

   拓展的方法如下:
  
 
  
// 总的来说就是拿到一个新的加上旧的空间,然后将旧的写到新申请的buf中,然后释放旧的
 
  
static ByteBuf expandCumulation(ByteBufAllocator alloc, ByteBuf cumulation, int readable) {
 
  
    ByteBuf oldCumulation = cumulation;
 
  
    cumulation = alloc.buffer(oldCumulation.readableBytes() + readable);
 
  
    cumulation.writeBytes(oldCumulation);
 
  
    oldCumulation.release();
 
  
    return cumulation;
 
  
}