一个框架之所以优秀,很重要的原因之一是设计者对每一处设计细节都做了充分的思考和优化,就像nginx之于lighttpd,jetty之于tomcat等等。缓存作为影响框架性能的一个重要因素,是每个优秀框架都要认真设计的方面,先看看JDK原生的Buffer结构:
简单来说JDK中的Buffer就分为两类,基于堆的Buffer和非基于堆(Native)的Buffer。
HeapByteBuffer是基于堆实现的,也就是利用JVM中字节数组byte[]实现了缓存;而DirectByteBuffer是基于Unix系统的MMap机制实现。
但是令人不解的是JDK中对于缓存的设计方式,既然ByteBuffer是HeapByteBuffer和MappedByteBuffer的公共抽象,为何还要将为HeapByteBuffer实现而添加的字节数组成员变量final byte[] hb放在抽象父类ByteBuffer中,更有意思的是,在最高层次的抽象类Buffer中竟然放置了其孙子类MappedByteBuffer所需要的变量long address,该变量会通过MMap直接映射到本地操作系统的文件地址,不过在JDK的注释中说明定义在这里是出于JNI操作的性能考虑,也许这也算作一种反模式吧。
Jetty的Buffer层次如下图所示:
Jetty的Buffer类型也可分为基于字节数组的IndirectNIOBuffer和基于Native MMap的DirectNIOBuffer,另外还有只读的View类型Buffer和支持文件随机访问的RandomAccessFileBuffer类型的Buffer。
整体上Jetty扩展了原生JDK的Buffer体系,加入了更多应对其特殊业务场景的功能和接口,对于其中一个non-direct的ByteArrayBuffer没有采用JDK的Buffer实现,而是自己造了轮子,大体实现思路和JDK一致,不过实现代码更为清晰,至于性能孰优孰略未经测试。
public class ByteArrayBuffer extends AbstractBuffer
{
final protected byte[] _bytes;
}
而对于direct buffer的实现,jetty则是对JDK的ByteBuffer进行了封装,没有自己实现。
public class DirectNIOBuffer extends AbstractBuffer implements NIOBuffer
{
protected final ByteBuffer _buf;
private ReadableByteChannel _in;
private InputStream _inStream;
private WritableByteChannel _out;
private OutputStream _outStream;
public DirectNIOBuffer(int size)
{
super(READWRITE,NON_VOLATILE);
_buf = ByteBuffer.allocateDirect(size);
_buf.position(0);
_buf.limit(_buf.capacity());
}
}
public class IndirectNIOBuffer extends ByteArrayBuffer implements NIOBuffer
{
protected final ByteBuffer _buf;
public IndirectNIOBuffer(int size)
{
super(size,READWRITE,NON_VOLATILE);
_buf = ByteBuffer.wrap(_bytes);
_buf.position(0);
_buf.limit(_buf.capacity());
}
}
IndirectNIOBuffer和DirectNIOBuffer都属于接口NIOBuffer的实现,NIOBuffer接口如下所示:
public interface NIOBuffer extends Buffer
{
public ByteBuffer getByteBuffer();
public boolean isDirect();
}
接口很简单,getByteBuffer方法用于获得java.nio包下面的ByteBuffer,而isDirect()则是为了区分该ByteBuffer是direct类型还是non-direct。
总结一下,Jetty的Buffer可以按照两个维度来划分
1. 按照是否自己造轮子划分。ByteArrayBuffer为自己实现;IndirectNIOBuffer和DirectNIOBuffer为java.nio.ByteBuffer的封装。
2. 按照direct or non-direct划分。ByteArrayBuffer和IndirectNIOBuffer为non-direct;DirectNIOBuffer为direct。
从Jetty的缓存池实现中的一段代码可以更容易理解:
public abstract class AbstractBuffers implements Buffers {
final protected Buffer newBuffer()
{
switch(_bufferType)
{
case BYTE_ARRAY:
return new ByteArrayBuffer(_bufferSize);
case DIRECT:
return new DirectNIOBuffer(_bufferSize);
case INDIRECT:
return new IndirectNIOBuffer(_bufferSize);
}
throw new IllegalStateException();
}
}