5.4 ByteBufHolder

通常,您有一个需要保留字节作为实际有效负载以及其他属性的对象。例如,表示HTTP响应的对象就是这样。您具有属性,例如状态码,Cookie等,还具有以字节表示的实际内容/有效负载。

由于这种情况很常见,因此Netty为其提供了一个额外的抽象,称为ByteBufHolder。好消息是,这使Netty也可以使用高级功能,例如缓冲池,其中保存实际数据的 ByteBuf 可以从池中借用,如果需要还可以自动释放。

实际上,ByteBufHolder只有少数几种方法可以访问其保存的数据,并且还可以使用引用计数。表5.7显示了它提供的方法(忽略在其超类型ReferenceCounted中声明的方法)。

Name

Description

data() 4.1.51是content()

Return the ByteBuf that holds the data.

copy()

Make a copy of the ByteBufHolder that does not share its data (so the data is also copied).

如果要实现一个将其有效载荷/数据存储在ByteBuf中的消息对象,那么使用ByteBufHolder总是一个好主意。

5.4.1 Netty的缓冲区实用程序类

使用JDK的NIO API的困难之一是执行看似简单的任务所需的大量“样板”代码。尽管Netty的各种Buf实现已经很容易使用,但Netty通过提供一组实用程序类而走得更远,这使得创建和使用各种缓冲区变得更加容易。在本节中,我将研究三个此类实用程序类,因为它们在您日常使用Netty时可能会很有用。

5.4.2 ByteBufAllocator--在需要时分配ByteBuf

如前所述,Netty支持各种ByteBuf实现的池化。为了实现这一点,它提供了一个称为ByteBufAllocator的抽象。顾名思义,它负责分配上述类型的ByteBuf实例。是否将它们合并到特定于实现中,但不会更改使用它的操作方式。

让我们首先看一下ByteBufAllocator提供的各种操作。表5.8对此进行了简要概述。

如您所见,这些方法带有一些额外的参数,这些参数使用户可以指定ByteBuf的初始容量和最大容量。您可能还记得,ByteBuf可以根据需要进行扩展。在达到最大容量之前,这是正确的。

您可以通过通道(理论上,每个通道可以具有另一个ByteBufAllocator)或通过绑定到执行代码的ChannelHandler的ChannelHandlerContext来获取它。有关ChannelHandler和ChannelHandlerContext的更多信息,请参见第6章。

Netty带有ByteBufAllocator的两种不同实现。一种实现方式是将ByteBuf实例池化,以最大程度地减少分配/取消分配的成本,并将内存碎片保持在最低水平。如何实现这些功能超出了本书的范围,但是让我注意到它基于jemalloc论文,因此使用与许多操作系统相同的算法来有效分配内存。

另一个实现根本不池化ByteBuf实例,并且每次都返回一个新实例。Netty默认情况下使用PooledByteBufAllocator(这是ByteBufAllocator的池实现),但是可以通过ChannelConfig更改它或在引导服务器时指定其他名称来轻松更改。有关更多详细信息,请参见第9章引导应用程序。

5.4.3 Unpooled--缓冲区创建变得容易

在某些情况下,由于您没有对ByteBufAllocator的引用,因此无法访问前面介绍的ByteBuf。对于此用例,Netty提供了一个名为Unpooled的实用程序类。此类包含用于创建未池化ByteBuf实例的静态帮助器方法

让我们快速浏览一下所提供的方法。在本节中,对它们全部解释都太多了,因此请参考API文档以获取所有这些的概述。

表5.9显示了最常用的Unpooled方法。

通过此Unpooled类,还可以更轻松地在Netty之外使用Netty的缓冲区API,这对于那些可以从高性能可扩展缓冲区API中受益但不需要Netty其他部分的项目很有用。

5.4.4 ByteBufUtil--小但有用

另一个有用的类是ByteBufUtil类。此类提供了静态帮助器方法,这些方法在ByteBuf上进行操作时非常有用。在前面提到的Unpooled类之外使用这些方法的主要原因之一是,这些方法是通用的,并且不依赖于是否被池化的ByteBuf。

也许最有价值的是hexdump()方法,它像此类中的其他方法一样作为静态方法提供。它所做的是以十六进制表示形式打印ByteBuf的内容。在多种情况下这可能很有用。一种是记录ByteBuf的内容以进行调试。十六进制值可以轻松地转换回实际的字节表示形式。您可能想知道为什么不直接打印字节。这里的问题是,这可能会导致一些难以阅读的日志条目。十六进制字符串更加用户友好。

除此之外,ByteBufUtil类还提供了一些方法来检查ByteBuf实现的等式以及在开始实现自己的ByteBuf时可能有用的其他方法。

最后更新于

这有帮助吗?