Nettys buffer API has two interfaces:
ByteBuf
ByteBufHolder
Whenever(每当) you need to interact(相互作用) with a remote peer such as a database, the communication needs to be done in bytes. For this and other reasons an efficient(高效), convenient, and easy-to-use data structure is required, and Netty's ByteBuf implementation meets these requirements and more, making it an ideal data container, optimized(最佳的) for holding and interacting with bytes. ByteBufis a data container that allows you to add/get bytes from it in an efficient way. To make it easier to operate, it uses two indices: one for reading and one for writing. This allows you to read data out of them in a sequential way and "jump" back to read it again. All you need to do is adjust(调整) the reader index and start the read operation again.
After something is written to the ByteBuf, its writerIndex is increased by the amount of bytes written. After you start to read bytes, its readerIndexis increased. You can read bytes until the writerIndex and readerIndex are at the same position. The ByteBuf then becomes unreadable, so the next read request triggers(触发) an IndexOutOfBoundsException similar to what youve seen when trying to read beyond the capacity of an array. Calling any of the buffers methods beginning with "read" or "write" automatically(自动的) advances the reader and writer indexes or you. There are also relative operations to set and get bytes. These dont move the indexes but operate on the relative(相对的) index that was given. A ByteBuf may have a maximum capacity(容量) to set an upper limit(上限) to the maximum data it can hold, trying to move the writer index beyond this capacity will result in an exception. The default limit is Integer.MAX_VALUE.
Figure 5.2 shows how a ByteBufis laid out.
As Figure 5.1 shows, a ByteBuf is similar to a byte array, the most notable(显著的) difference being the addition of the read and write indices which can be used to control access to the buffer's data. Youll learn more about the operations that can be performed on a ByteBuf in a later section. For now, keep this in mind and lets review the different types of ByteBufthat youll most likely use.
There are three different types of ByteBuf youll encounter when using Netty (there are more, but these are used internally). You may end up implementing your own, but this is out of scope here. Lets look at the provided types that you are most likely interested in.
The most used type is the ByteBuf that stores its data in the heap space(堆内存) of the JVM. This is done by storing it in a backing array. This type is fast to allocate and also de-allocate when you're not using a pool. It also offers a way to directly access the backing array, which may make it easier to interact with legacy(遗留的) code.
Another ByteBuf implementation is the direct one.Direct means that it allocates the memory directly, which is outside the heap. You won't see its memory usage in your heap space. You must take this into account when calculating the maximum amount of memory your application will use and how to limit it, as the max heap size won't be enough. Direct buffers on the other side are optimal(最佳的,最优的) when its time to transfer data over a socket. In fact, if you use a nondirect buffer, the JVM will make a copy of your buffer to a direct buffer internally(实质上) before sending it over the socket. The down side of direct buffers is that they're more expensive to allocate(分配) and de-allocate compared to heap buffers. This is one of the reasons why Netty supports pooling, which makes this problem disappear. Another possible down side can be that you're no longer able to access the data via the backing array, so you'll need to make a copy of the data if it needs to work with legacy code that requires this. The following listing shows how you can get the data in an array and call your method even without the ability to access the backing array directly.
The last ByteBuf implementation you may be confronted(面对的) with is the CompositeByteBuf. This does exactly what its name says; it allows you to compose different ByteBuf instances and provides a view over them. The good thing is you can also add and remove them on-the-fly(在传输过程中), so its kind of like a List. If youve ever worked with the JDK's ByteBuffer you've most likely missed such a feature there. As the CompositeByteBufis just a view over others, the hasArray() method will return false because it may contain several ByteBuf instances of both direct and nondirect types. For example, a message could be composed of two parts: header and body. In a modularized application, the two parts could be produced by different modules and assembled later when the message is sent out. Also, you may use the same body all the time and just change the header. So it would make sense here to not allocate a new buffer every time. This would be a perfect fit for a CompositeByteBuf as no memory copy will be needed and the same API could be used as with non-composite buffers.
Figure 5.2 shows how a CompositeByteBuf would be used to compose(组成) the header and body.
======END======