netty(十二)源码分析之ByteBuf 四

PooledDirectByteBuf基于内存池实现,与UnPooledDirectByteBuf的唯一不同就是缓冲区的分配与销毁策略不同,其他功能都是等同的,也就是说,两者唯一的不同就是内存分配策略不同。
1.创建字节缓冲区实例

由于采用内存池实现,所以新创建PooledDerectByteBuf对象时不能直接new一个实例,而是从内存池中获取,然后设置引用计数器的值,

    static PooledDirectByteBuf newInstance(int maxCapacity) {
        PooledDirectByteBuf buf = RECYCLER.get();
        buf.reuse(maxCapacity);
        return buf;
    }

    final void reuse(int maxCapacity) {
        maxCapacity(maxCapacity);
        setRefCnt(1);
        setIndex0(0, 0);
        discardMarks();
    }

直接从内存池Recycler<PooledDirectByteBuf>中获取PooledDirectByteBuf对象,然后设置它的引用计数器为1,设置缓冲区最大容量后返回。设置readerIndex,writerIndex与相应mark都为0.

ByteBuf相关的辅助类功能介绍

ByteBufHolder

ByteBufHolder是ByteBuf的容器,在Netty中,它非常有用。例如HTTP协议的请求消息和应答消息都可以携带消息体,这个消息体在NIO ByteBuffer中就是个ByteBuffer对象,在Netty中就是ByteBuf对象。由于不同的协议消息体可以包含不同的协议字段和功能,因此,需要对ByteBuf进行包装和抽象,不同的子类可以有不同的实现。
为了满足这些定制化的需求,Netty抽象出了ByteBufHolder对象,它包含了一个ByteBuf,另外还提供了一些其他实用的方法,使用者集成ByteBufHolder接口后可以按需封装自己的实现。相关类库的继承关系如下图所示:

ByteBufAllocator

ByteBufAllocator是字节缓冲区分配器,按照Netty的缓冲区实现不同,共有两种不同的分配器:基于内存池的字节缓冲区分配器和普通的字节缓冲区分配器。接口的继承关系如下图所示:

下面我们给出ByteBufAllocator的主要API功能列表



CompositeByteBuf

CompositeByteBuf允许将多个ByteBuf的实例组装到一起,形成一个统一的视图,有点类似于数据库将多个表的字段组装到一起统一用视图展示。

CompositeByteBuf在一些场景下非常有用,例如某个协议POJO对象包含两部分:消息头和消息体,它们都是ByteBuf对象。当需要对消息进行编码的时候需要进行整合,如果使用JDK的默认能力,有以下两种方式。

(1)将某个ByteBuffr复制到另一个ByteBuffer中,或者创建一个新的ByteBuffer,将两者复制到新建的ByteBuffer中;
(2)通过List或数组等容器,将消息头和消息体放到容器中进行统一维护和处理。

上面的做法非常别扭,实际上我们遇到的问题跟数据库中视图解决的问题一致————缓冲区有多个,但是需要统一展示和处理,必须有存放它们的统一容器。为了解决这个问题,Netty提供了CompositeByteBuf。
其实现如下:

public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements Iterable<ByteBuf> {

    private static final ByteBuffer EMPTY_NIO_BUFFER = Unpooled.EMPTY_BUFFER.nioBuffer();
    private static final Iterator<ByteBuf> EMPTY_ITERATOR = Collections.<ByteBuf>emptyList().iterator();

    private final ByteBufAllocator alloc;
    private final boolean direct;
    private final List<Component> components;
    private final int maxNumComponents;

    private boolean freed;
它定义了一个Component类型的集合,实际上Component就是ByteBuf的包装实现类,它聚合了ByteBuf对象,维护了在集合中的位置偏移量信息等,它的实现如下:

private static final class Component {
        final ByteBuf buf;
        final int length;
        int offset;
        int endOffset;

        Component(ByteBuf buf) {
            this.buf = buf;
            length = buf.readableBytes();
        }

        void freeIfNecessary() {
            buf.release(); // We should not get a NPE here. If so, it must be a bug.
        }
    }

向CompositeByteBuf中新增一个ByteBuf的代码,如下所示:

    public CompositeByteBuf addComponent(boolean increaseWriterIndex, ByteBuf buffer) {
        checkNotNull(buffer, "buffer");
        addComponent0(increaseWriterIndex, components.size(), buffer);
        consolidateIfNeeded();
        return this;
    }

删除增加的ByteBuf源码,如下所示:

    public CompositeByteBuf removeComponent(int cIndex) {
        checkComponentIndex(cIndex);
        Component comp = components.remove(cIndex);
        comp.freeIfNecessary();
        if (comp.length > 0) {
            // Only need to call updateComponentOffsets if the length was > 0
            updateComponentOffsets(cIndex);
        }
        return this;
    }

ByteBufUtil是一个非常有用的工具类,它提供了一系列静态方法用于操作ByteBuf对象。它的功能列表如下:

(1)encodeString(ByteBufAllocator alloc,CharBuffer src,Charset charset):对需要编码的字符串src按照指定的字符集charset进行编码,利用指定的ByteBufAllocator生成一个新的ByteBuf;
(2)decodeString(ByteBuffer src,Charset charset):使用指定的ByteBuffer和charset进行对ByteBuffer进行编码,获取编码后的字符串。

还有一个非常有用的方法就是hexDump,它能够将参数ByteBuf的内容以十六进制字符串的方式打印出来,用于输出日志或者打印码流,方便问题定位,提升系统的可维护性。

总结:
我们介绍了与ByteBuf密切相关的工具类和辅助类。ByteBuf是Netty架构中最重要,最基础的数据结构,熟练地掌握和使用它是学好Netty的基本要求,也是成长为高级Netty开发人员的必经之路。后面我们一起研究Netty的另两个重要类库:Channel和Unsafe。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值