MINA2官方教程翻译(5) 基本概念之IoBuffer
简介
IoBuffer是MINA应用程序中使用的一种字节缓冲区,它是JDK中ByteBuffer类的替代品。MINA框架出于下面两个原因没有直接使用JDK中nio包内的ByteBuffe:
- 没有提供可用的getters和putters方法,例如fill, get/putString, 和get/putAsciiInt();
- 由于它的容量是固定的,所以不利于存储变长数据。
MINA 3 将改变这种情况。MINA框架对nio ByteBuffer做了一层封装的最主要原因是希望能够拥有一种可扩展的缓冲区。这并不是一个很好的决定。缓冲区就是缓冲区:一个用于存储临时数据的临时空间,直到这些数据被使用。其实还有些其他的解决方案,例如可以对一组nio ByteBuffer进行包装来避免数据从一个缓冲区向两个容量更大的缓冲区复制,从而得到一个容量可扩展的缓冲区。
或许在filter之间传递数据时使用InputStrea来代替字节缓冲区会更加舒适,因为这不需要提供一种可以存储数据的特性,这种数据结构可以使字节数组、字符串或者其他类型的消息等等。
最后,但并非最不重要的一点是,当前的实现并没有达成一个目标:零拷贝策略(例如当我们从socket中读取了一些数据,我们希望避免持续的数据拷贝)。如果我们使用了可以扩展的字节缓冲区,那么我们只需要在管理大数据消息时进行数据拷贝。请记住MINA ByteBuffer只不过是NIO ByteBuffer的顶层封装,当我们使用direct buffers时,很可能是一个很严重的问题。
IoBuffer 操作
分配一个新的Buffer
IoBuffer是一个抽象类,所以它不能直接被实例化。分配IoBuffer,我们可以使用两种allocate()方法。
// Allocates a new buffer with a specific size, defining its type (direct or heap)public static IoBuffer allocate(int capacity, boolean direct)// Allocates a new buffer with a specific sizepublic static IoBuffer allocate(int capacity)
allocate()方法是用一个或两个参数。第一种形式使用两个参数:
- capacity - buffer的容量
- direct -buffer的类型。true意味着得到一个direct buffer,false 意味着得到一个heap buffer
默认的buffer分配是由SimpleBufferAllocator处理的。
可选的, 下面的形式也可以使用:
IoBuffer buffer = IoBuffer.allocate(8);buffer.setAutoExpand(true);buffer.putString("12345678", encoder); // Add more to this bufferbuffer.put((byte)10);
按照上面的例子,如果数据的长度大于8byte的话,IoBuffe会根据情况重新分配其内置的ByteBuffer,它的容量会被加倍,它的limit会增长到String被写入时的最后position。这种行为与StringBuffer工作的方式十分类似。
注意:这种程序结构在MINA3.0时会被废弃,因为这并不是增长buffer容量的最好方式。这种方式很可能被一种类似InputStream的方式所替代,在InputStream的背后很可能是一组固定长度的ByteBuffers。
创建自动收缩的Buffer
为了节省内存,在有些情形下我们需要释放被额外分配的内存,IoBuffer提供了autoShrink属性来达到此目的。如果autoShrink属性被打开,当compact()方法被调用时,IoBuffer回将部分的回收其容量,只使用四分之一或是更少的容量。如果需要手动控制收缩行为,请使用shrink()方法。
让我们实践一下:
IoBuffer buffer = IoBuffer.allocate(16);buffer.setAutoShrink(true);buffer.put((byte)1);System.out.println("Initial Buffer capacity = "+buffer.capacity());buffer.shrink();System.out.println("Initial Buffer capacity after shrink = "+buffer.capacity());buffer.capacity(32);System.out.println("Buffer capacity after incrementing capacity to 32 = "+buffer.capacity());buffer.shrink();System.out.println("Buffer capacity after shrink= "+buffer.capacity());
我们初始化分配一个容量为16的buffer,并将自动收缩设置为true。
让我们看一下输出的结果:
Initial Buffer capacity = 16Initial Buffer capacity after shrink = 16Buffer capacity after incrementing capacity to 32 = 32Buffer capacity after shrink= 16
让我们分析一下输出:
- 初始化buffer的容量为16,因为我们使用16指定了该buffer的容量,16也就成了该buffer的最小容量
- 调用shrink()方法后,容量仍旧为16,所以无论怎么调用紧缩方法,容量都不好小于其初始容量
- 增加该buffer的容量至32,该buffer的容量达到32
- 调用shrink()方法,容量回收至16,从而剔除了冗余的容量
再次强调,这种方式是一种默认的行为,我们不需要明确指明一个buffer是否能被收缩。
Buffer分配
IoBufferAllocater负责分配并管理buffer,如果你希望使用你的方式精确控制分配行为,请自己实现IoBufferAllocater接口。
MINA提供了IoBufferAllocater的两种实现,如下:
- SimpleBufferAllocator (默认) - 每次创建一个新的buffer
- CachedBufferAllocator - 缓存buffer,使buffer在扩展时可以被重用
注意:在新版本的JVM中,使用cached IoBuffer并不能明显提高性能。
你可以自己实现IoBufferAllocator接口并在IoBuffer上调用setAllocator()方法来指定使用你的实现。