Netty三大要素,ByteBuf、零拷贝机制、职责链

Netty高效缓冲区ByteBuf

Netty 的ByteBuf定义了三个属性:写下标(writerIndex),读下标(readerIndex)、容量大小(capacity),ByteBuf的操作由三个属性完成。

  • 超出capacity动态扩容
  • 丰富的api
//1、创建非池化的ByteBuf 大小设置为10
        ByteBuf byteBuf= Unpooled.buffer(10);
        //原始ByteBuf*************>UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 10)
        System.out.println("原始ByteBuf*************>"+byteBuf.toString());
        //ByteBuf内容为**********>[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        System.out.println("ByteBuf内容为**********>"+ Arrays.toString(byteBuf.array()));

        //2 写入内容
        byte[] bytes="Dawn".getBytes();
        byteBuf.writeBytes(bytes);
        //写入的bytes为*********>[68, 97, 119, 110]
        System.out.println("写入的bytes为*********>"+Arrays.toString(bytes));
        //写入内容后ByteBuf为*********>UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 4, cap: 10)
        System.out.println("写入内容后ByteBuf为*********>"+byteBuf.toString());
        //ByteBuf的内容为***********>[68, 97, 119, 110, 0, 0, 0, 0, 0, 0]
        System.out.println("ByteBuf的内容为***********>"+Arrays.toString(byteBuf.array()));

        //3 读取内容
        byte content1=byteBuf.readByte();
        byte content2=byteBuf.readByte();
        //读取的内容为:[68, 97]
        System.out.println("读取的内容为:"+Arrays.toString(new byte[]{content1,content2}));
        //读取内容后ByteBuf:UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 2, widx: 4, cap: 10)
        System.out.println("读取内容后ByteBuf:"+byteBuf.toString());
        //ByteBuf内容为[68, 97, 119, 110, 0, 0, 0, 0, 0, 0]
        System.out.println("ByteBuf内容为"+Arrays.toString(byteBuf.array()));

        //4 将读取过的内容丢弃
        byteBuf.discardReadBytes();
        //将读取过的内容丢弃后ByteBuf:UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 2, cap: 10)
        System.out.println("将读取过的内容丢弃后ByteBuf:"+byteBuf.toString());
        //ByteBuf的内容为:[119, 110, 119, 110, 0, 0, 0, 0, 0, 0]
        System.out.println("ByteBuf的内容为:"+Arrays.toString(byteBuf.array()));

        //5 清空读写指针
        byteBuf.clear();
        //将读写指针清空后ByteBuf:UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 10)
        System.out.println("将读写指针清空后ByteBuf:"+byteBuf.toString());
        //ByteBuf 的内容为:[119, 110, 119, 110, 0, 0, 0, 0, 0, 0]
        System.out.println("ByteBuf 的内容为:"+Arrays.toString(byteBuf.array()));

        //6 写入内容
        byte[] bytes1="On".getBytes();
        byteBuf.writeBytes(bytes1);
        //写入的bytes:[79, 110]
        System.out.println("写入的bytes:"+Arrays.toString(bytes1));
        //写入内容后ByteBuf:UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 2, cap: 10)
        System.out.println("写入内容后ByteBuf:"+byteBuf.toString());
        //ByteBuf的内容:[79, 110, 119, 110, 0, 0, 0, 0, 0, 0]
        System.out.println("ByteBuf的内容:"+Arrays.toString(byteBuf.array()));

        // 7 将ByteBuf清零
        byteBuf.setZero(0,byteBuf.capacity());
        //内容清零后ByteBuf:UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 2, cap: 10)
        System.out.println("内容清零后ByteBuf:"+byteBuf.toString());
        //ByteBuf的内容:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        System.out.println("ByteBuf的内容:"+Arrays.toString(byteBuf.array()));

        // 8 写入超过10容量大小的字符串,动态扩容
        byte[] inputeContent="Come on,Dawn.".getBytes();
        byteBuf.writeBytes(inputeContent);
        //写入的bytes:[67, 111, 109, 101, 32, 111, 110, 44, 68, 97, 119, 110, 46]
        System.out.println("写入的bytes:"+Arrays.toString(inputeContent));
        //写入超过容量后的ByteBuf:UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 15, cap: 64)
        System.out.println("写入超过容量后的ByteBuf:"+byteBuf.toString());
        //ByteBuf的内容:[0, 0, 67, 111, 109, 101, 32, 111, 110, 44, 68, 97, 119, 110, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        System.out.println("ByteBuf的内容:"+Arrays.toString(byteBuf.array()));
  • 动态扩容实现原理
    当写入数据超过定义ByteBuf的capacity时动态库容,每当想ByteBuf写入数据会计算最小所需容量minNewCapacity(writerIndex+写入的字符长度)。当超过默认阈值(threshold=4M)时,容量扩展逻辑为最新所需容量除阈值再剩阈值再加阈值;当最小所需容量小于阈值时,容量扩展逻辑为,默认值为64个字节,当最小容量小于64个字节,扩容到64字节。大于64字节时时候64*2的n次的库容。
  • 动态扩容源码分析
// minNewCapacity为写下标值wrinterIndex+写入输入的字节长度,maxCapicty为Int类型最大的字节数
 public int calculateNewCapacity(int minNewCapacity, int maxCapacity) {
        if (minNewCapacity < 0) {
            throw new IllegalArgumentException("minNewCapacity: " + minNewCapacity + " (expected: 0+)");
        }
        if (minNewCapacity > maxCapacity) {
            throw new IllegalArgumentException(String.format(
                    "minNewCapacity: %d (expected: not greater than maxCapacity(%d)",
                    minNewCapacity, maxCapacity));
        }
        //默认阈值为4M
        final int threshold = CALCULATE_THRESHOLD; // 4 MiB page
   
        if (minNewCapacity == threshold) {
            return threshold;
        }

        // 所需最小容量大于阈值时
        if (minNewCapacity > threshold) {
            int newCapacity = minNewCapacity / threshold * threshold;
            if (newCapacity > maxCapacity - threshold) {
                newCapacity = maxCapacity;
            } else {
                newCapacity += threshold;
            }
            return newCapacity;
        }

        //  // 所需最小容量小于阈值时,默认最小库容从64字节开始
        int newCapacity = 64;
        // 扩容规则:扩容值(库容值从64*2开始,扩容值=库容值*2)*2,直到扩容值大于或等于最小所需容量
        while (newCapacity < minNewCapacity) {
            newCapacity <<= 1;
        }

        return Math.min(newCapacity, maxCapacity);
    }

Netty 零拷贝机制

  • 零拷贝机制
 // 改变byteBuf 具体某个的字节
        byte[] arr={1,2,3,4,5,6};
        // 包装数组,数组转为bytebuf缓存区
        ByteBuf byteBuf = Unpooled.wrappedBuffer(arr);
        System.out.println(byteBuf.getByte(5));
        arr[5]= 7;
        System.out.println(byteBuf.getByte(5));

        // 拆包
        ByteBuf sliceByteBuf = Unpooled.wrappedBuffer("Nothing is impossible".getBytes());

        ByteBuf newByteBuf = sliceByteBuf.slice(0,7);
        //如果该缓冲区是另一个缓冲区的包装器,则返回底层缓冲区实例
        newByteBuf.unwrap();
        System.out.println(newByteBuf.toString());
        System.out.println(new String(new byte[]{newByteBuf.getByte(6)}));
        // 容器大小7
        System.out.println(newByteBuf.capacity());
        //UnpooledSlicedByteBuf(ridx: 0, widx: 7, cap: 7/7, unwrapped: UnpooledHeapByteBuf(ridx: 0, widx: 21, cap: 21/21))
        System.out.println(sliceByteBuf.toString());

        //复合缓存区
        ByteBuf byteBufOne = Unpooled.buffer(6);
        byteBufOne.writeByte(3);
        ByteBuf byteBufTwo = Unpooled.buffer(2);
        byteBufTwo.writeByte(5);
        //返回一个新的没有组件的big-endian复合缓冲区
        CompositeByteBuf compositeByteBuf=Unpooled.compositeBuffer();
        CompositeByteBuf newBuf=compositeByteBuf.addComponents(true,byteBufOne,byteBufTwo);
        //CompositeByteBuf(ridx: 0, widx: 2, cap: 2, components=2)
        System.out.println(newBuf);

职责链实现原理

职责链三大要素:抽象处理器,处理器上下文(维护处理器上下文及执行处理器),处理器具体实现

  • 抽象处理器
abstract class AbstractHandler {
    //handler 方法,处理器
    abstract void doHanlder(HandlerChainContext handlerChainContext, Object object);
}
  • Handler处理器上下文
public class HandlerChainContext {
    // 下一个节点
    HandlerChainContext next;
    // 抽象处理方法
    AbstractHandler abstactHandler;

    // 构造函数 给handler赋值
    public HandlerChainContext(AbstractHandler handler) {
        this.abstactHandler = handler;
    }

    // 处理方法
    void handler(Object obj){
        this.abstactHandler.doHanlder(this,obj);
    }

    /*
    * 执行下一个handler
    * */
    void runNext(Object object){
        if(this.next!=null){
            this.next.handler(object);
        }
    }
}
  • 具体处理器实现
public class DawnHandler extends AbstractHandler {
    @Override
    void doHanlder(HandlerChainContext handlerChainContext, Object object) {
        object=object.toString()+" Dawn handler ";
        System.out.println(" Handler one:"+object);
        // 执行下一个
        handlerChainContext.runNext(object);
    }
}
  • 职责链实例
  // 初始化时候构造一个head 作为责任链的开始 但并没有具体执行
    public HandlerChainContext head= new HandlerChainContext(new AbstractHandler() {
        @Override
        void doHanlder(HandlerChainContext handlerChainContext, Object object) {
            handlerChainContext.runNext(object);
        }
    });

    // 从头节点开始请求执行
    public void requestProcess(Object object){
        this.head.handler(object);
    }

    // 在职责链尾部新增处理器
    public void addLast(AbstractHandler handler){
        HandlerChainContext context=head;
        // 保证context为最后一个节点
        while (context.next!=null){
            context=context.next;
        }
        context.next=new HandlerChainContext(handler);
    }

    public static void main(String[] args) {
        //构建职责链
        DawnPipeline dawnPipeline=new DawnPipeline();
        dawnPipeline.addLast(new DawnHandler());
        dawnPipeline.addLast(new StarHandler());
        dawnPipeline.addLast(new DawnHandler());
        dawnPipeline.addLast(new StarHandler());
        dawnPipeline.addLast(new DawnHandler());
        // 执行职责链
        dawnPipeline.requestProcess("Come on,Dawn!");
    }

总结

本文介绍了Netty的高效的ByteBuf 基本使用、动态库容原理,通过零拷贝机制的示例,职责链实现原理示例,可以初步理解什么是netty的零拷贝机制及职责链的使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值