Netty 的 ByteBuffer 替代品是 ByteBuf,一个强大的实现,既解决了 JDK API 的局限性,又为网络应用程序的开发者提供了更好的 API。
1、ByteBuf与ByteBuffer的对比
ByteBuffer的缺点:
(1)ByteBuffer的字节数组是被定义成final的,也就是长度固定。一旦分配完成就不能扩容和收缩,灵活性低,而且当待存储的对象字节很大可能出现数组越界,用户使用起来稍不小心就可能出现异常。
(2)ByteBuffer只用了一个position指针来标识位置,读写模式切换时需要调用flip()函数和rewind()函数,使用起来需要非常小心,不然很容易出错误。
ByteBuf的优点:
(1)ByteBuf是吸取ByteBuffer的缺点之后重新设计,存储字节的数组是动态的,最大是Integer.MAX_VALUE。这里的动态性存在write操作中,write时得知buffer不够时,会自动扩容。
(2) ByteBuf的读写索引分离,使用起来十分方便。此外ByteBuf还新增了很多方便实用的功能。
2、ByteBuf的结构
ByteBuf通过两个指针协助读写操作,读操作使用readerIndex,写操作使用writerIndex。
readerIndex、writerIndex初始值是0,写入数据时writerIndex增加,读取数据时readerIndex增加,但是readerIndex不会超过writerIndex。
读取之后,0-readerIndex之间的空间视为discard的,调用discardReadByte方法可以释放这一部分空间,作用类似于ByteBuffer的compact方法。
readerIndex-writerIndex之间的数据是可读的,等价于ByteBuffer中position~limit之间的数据。
writerIndex-capacity之间的空间是可写的,等价于ByteBuffer中limit~capacity之间的空间。
读只影响readerIndex、写只影响writerIndex,读写之间不需要调整指针位置,所以相较于NIO的ByteBuffer,可以极大的简化读写操作。
3、ByteBuf 分配
Netty 提供了一个简单的称为Unpooled 的工具类,它提供了静态的辅助方法来创建未池化的ByteBuf实例。
4、示例程序
@Test
public void test(){
ByteBuf byteBuf = Unpooled.buffer(32);
System.out.println(String.format("初始状态 readerIndex:%s,writerIndex:%s,capacity:%s",
byteBuf.readerIndex(),byteBuf.writerIndex(),byteBuf.capacity()));
byteBuf.writeBytes("hello".getBytes());
System.out.println(String.format("写入hello readerIndex:%s,writerIndex:%s,capacity:%s",
byteBuf.readerIndex(),byteBuf.writerIndex(),byteBuf.capacity()));
ByteBuf helloBuf = Unpooled.buffer(5);
//读取到helloBuf中
byteBuf.readBytes(helloBuf);
//将helloBuf中所有的字节转为字符串
System.out.println("读取到的数据:"+helloBuf.toString(CharsetUtil.UTF_8));
System.out.println(String.format("读取hello后 readerIndex:%s,writerIndex:%s,capacity:%s",
byteBuf.readerIndex(),byteBuf.writerIndex(),byteBuf.capacity()));
//再次写入
byteBuf.writeBytes("abcdef".getBytes());
System.out.println(String.format("写入abcdef后 readerIndex:%s,writerIndex:%s,capacity:%s",
byteBuf.readerIndex(),byteBuf.writerIndex(),byteBuf.capacity()));
//丢弃之前读过的字节
byteBuf.discardReadBytes();
System.out.println(String.format("discardReadBytes后 readerIndex:%s,writerIndex:%s,capacity:%s",
byteBuf.readerIndex(),byteBuf.writerIndex(),byteBuf.capacity()));
//清空缓存区
byteBuf.clear();
System.out.println(String.format("clear readerIndex:%s,writerIndex:%s,capacity:%s",
byteBuf.readerIndex(),byteBuf.writerIndex(),byteBuf.capacity()));
}
分析
1、写入hello后
2、读取hello的数据后
3、再次写入abcdef
4、丢弃到已读过的字节hello
5、clear后清空缓冲区
ByteBuf的相关api介绍:
更多api的使用可以查看ByteBuf提供的相关方法或者netty的文档。