• Netty源码分析第7章(编码器和写数据)---->第2节: MessageToByteEncoder


     

    Netty源码分析第七章: Netty源码分析

     

    第二节: MessageToByteEncoder

     

    同解码器一样, 编码器中也有一个抽象类叫MessageToByteEncoder, 其中定义了编码器的骨架方法, 具体编码逻辑交给子类实现

    解码器同样也是个handler, 将写出的数据进行截取处理, 我们在学习pipeline中我们知道, 写数据的时候会传递write事件, 传递过程中会调用handler的write方法, 所以编码器码器可以重写write方法, 将数据编码成二进制字节流然后再继续传递write事件

    首先看MessageToByteEncoder的类声明:

    public abstract class MessageToByteEncoder<I> extends ChannelOutboundHandlerAdapter{
        //省略类体
    }

    这里继承ChannelOutboundHandlerAdapter, 说明是个outBoundhandler, 我们知道write事件是个outBound事件, 而outBound事件只能通过outBoundHandler进行传输

    write事件传播过程中要调用handler的write方法

    我们跟到MessageToByteEncoder的write方法中:

    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        ByteBuf buf = null;
        try {
            if (acceptOutboundMessage(msg)) {
                @SuppressWarnings("unchecked")
                I cast = (I) msg;
                buf = allocateBuffer(ctx, cast, preferDirect);
                try {
                    encode(ctx, cast, buf);
                } finally {
                    ReferenceCountUtil.release(cast);
                }
    
                if (buf.isReadable()) {
                    ctx.write(buf, promise);
                } else {
                    buf.release();
                    ctx.write(Unpooled.EMPTY_BUFFER, promise);
                }
                buf = null;
            } else {
                ctx.write(msg, promise);
            }
        } catch (EncoderException e) {
            throw e;
        } catch (Throwable e) {
            throw new EncoderException(e);
        } finally {
            if (buf != null) {
                buf.release();
            }
        }
    }

    首先通过 if (acceptOutboundMessage(msg)) 判断当前对象是否可处理

    如果可处理, 则进入if块中的逻辑, 如果不能处理, 则进入else块, 通过ctx.write(msg, promise)继续传递write事件

    我们看if块中

     I cast = (I) msg 这里是强制类型转换, 转换成I类型, I类型是个泛型, 具体类型由用户定义

     buf = allocateBuffer(ctx, cast, preferDirect) 这里进行缓冲区分配

    跟到allocateBuffer方法中:

    protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, @SuppressWarnings("unused") I msg, 
                               boolean preferDirect) throws Exception {
        if (preferDirect) {
            return ctx.alloc().ioBuffer();
        } else {
            return ctx.alloc().heapBuffer();
        }
    }

    这里会直接通过ctx的内存分配器进行内存分配, 通过判断preferDirect来分配堆内存或者堆外内存, 默认情况下是分配堆外内存

    有关内存分配, 我们之前已经做过相关的剖析

    回到write方法中:

    内存分配结束之后会调用encode(ctx, cast, buf)方法进行编码, 该类由子类实现

    子类可以通过继承该类, 重写encode方法, 将参数对象cast编码成字节写入到传入的ByteBuf中, 就完成了编码工作

    编码完成后后, 会通过ReferenceCountUtil.release(cast)将cast对象释放

     if (buf.isReadable()) 这里判断buf是否有可读字节, 如果有可读字节, 则继续传递write事件

    如果没有可读字节, 则将buf进行释放, 继续传播write事件, 传递一个空的ByteBuf

    最后将buf设置为空

    以上就是有关抽象编码器的抽象逻辑, 具体的编码逻辑还需要其子类去做

     

    上一节: writeAndlush事件传播

    下一节: 写buffer队列

     

  • 相关阅读:
    linux 中实现两列数据的互换
    linux中 sort h的作用
    max 内置函数,管理uv 编辑器下面的窗口的显示情况
    时时设定 uv 面板的位置,还有就是 关于属性打开界面的大小
    判断贴图大小很好 同时可以判断文件大小
    两条线中画终点
    锁定控制器,一般在绑定的时候很多用到
    用 脚本编辑器读脚本 也是编辑脚本
    进行随机旋转用于和并东西并
    排列顶点 uv 不过有很大问题
  • 原文地址:https://www.cnblogs.com/xiangnan6122/p/10208131.html
Copyright © 2020-2023  润新知