上一篇《总体解读》的延续。。 java
在阅读IoBuffer源码以前,咱们先看Mina对IoBuffer的描述:A byte buffer used by MINA applications. This is a replacement for ByteBuffer. 这是一个对ByteBuffer的replacement,一样是用做缓冲区,作内容的切换和承载的容器,为何要用从新封装ByteBuffer,MINA是这么给出解释的Two Reasons: 面试
l It doesn't provide useful getters and putters 算法
l It is difficult to write variable-length data due to its fixed capacity apache
用过ByteBuffer的人可能常常会遇到BufferOverflowException这样的异常,缘由是buffer在初始化allocate以后就不能再自动的改变大小了,若是项目很规整,约定的很好,那可能不太会出意外,怕就怕项目一大,好多东西就乱套了。因此在阅读IoBuffer源码的时候,咱们会着重看它和ByteBuffer之间的差别。另一点,就是IoBuffer做为一个应用框架的工具,必然会提供比原生Buffer更便捷的方法,好比IoBuffer中能够直接put和get String,能够直接将内容转成十六进制等等。 数组
用法很简单,我却是想从如何将一个已有的类进行封装和扩展的角度来看IoBuffer的源码。在看MINA的源码以前,咱们有必要稍稍回顾一下ByteBuffer的构成: app
ByteBuffer继承了Buffer类,这个继承关系约定了Buffer系列中特定的操做形式(有点儿像指针),limit/position/mark/capacity,以及在遍历中使用的hasRemaining。而后经过两个静态方法来构建出ByteBuffer: 框架
使用Heap空间,堆空间的构造采用申请byte数组: 分布式
public static ByteBuffer allocate(int capacity) { if (capacity < 0) throw new IllegalArgumentException(); return new HeapByteBuffer(capacity, capacity); }
使用direct memory,这块内存的开辟就比较麻烦了,好多都是采用了Bit和native的方法: ide
public static ByteBuffer allocateDirect(int capacity) { return new DirectByteBuffer(capacity); }
除了构造以外,剩下的主要是对数据的操做方法,wrap、get和put,下面的图没有截全,还有好多方法: 工具
IoBuffer及其相关的类均在org.apache.mina.core.buffer下,IoBuffer定义了buffer使用的规则,AbseractIoBuffer提供了具体的实现:
IoBuffer没有继承任何类,只是实现了comparable接口,咱们注意到IoBuffer类修饰符用的是abstract,跟ByteBuffer也是用abstract修饰,至于为何要用abstract,我以为也容易理解,毕竟这是一个要对外直接使用的类,同时须要对实现进行规则和扩展:
public abstract class IoBuffer implements Comparable<IoBuffer>
在IoBuffer的一系列代码阅读中,你能够看到抽象类之间的继承,内部类的使用状况等等,后面,我会经过一个删减版的例子来盘点这中间的关系,因此大片的源码就不贴了。
UML工具不会用,关键是怕用错了,仍是用PPT画了。囧一个,你们有好那种能够一键生成的工具推荐一下,我以前用的是JUDE和Visio。上图画出了IoBuffer中几个重要类之间的关系,两个内部类均继承了AbstractIoBuffer,AbstractIoBuffer和IoBufferWrapper均实现了IoBuffer中的具体操做部分。IoBufferAllocator接口主要定义了为缓冲区开辟空间的方法,因此IoBuffer中须要引用来自IoBufferAllocator的对象。
在IoBuffer中,咱们熟知的allocate和wrap方法被声明成了static,经过引用IoBufferAllocator接口中的对象来实现,而其余诸如get、put等操做的方法都定义为abstract了,让其子类得以实现。IoBuffer中咱们还值得关注的主要见我以前写过的一篇文章《IoBuffer和ByteBuffer》。
下面是这些中产生buffer的接口IoBufferAllocator和其实现类:
接口很简单,就定义了几个在IoBuffer中已经被static修饰的方法。有两个类都实现了IoBufferAllocator,可是在IoBuffer中使用的是SimpleBufferAllocator:
/** The allocator used to create new buffers */ private static IoBufferAllocator allocator = new SimpleBufferAllocator(); /** A flag indicating which type of buffer we are using : heap or direct */ private static boolean useDirectBuffer = false;
因此咱们主要关注SimpleBufferAllocator:
public IoBuffer allocate(int capacity, boolean direct) { return wrap(allocateNioBuffer(capacity, direct)); } public ByteBuffer allocateNioBuffer(int capacity, boolean direct) { ByteBuffer nioBuffer; if (direct) { nioBuffer = ByteBuffer.allocateDirect(capacity); } else { nioBuffer = ByteBuffer.allocate(capacity); } return nioBuffer; } public IoBuffer wrap(ByteBuffer nioBuffer) { return new SimpleBuffer(nioBuffer); } public void dispose() { // Do nothing }
这是接口中定义的几个方法,这里调用内部类SimpleBuffer来生成相应的buffer,又因为SimpleBuffer继承了AbstractIoBuffer,因此真正实现的代码在AbstractIoBuffer中(这里有点儿绕,你们结合上面的图和源码一块儿读)。并且注意构造方法的protected关键字的使用:
private ByteBuffer buf; protected SimpleBuffer(ByteBuffer buf) { super(SimpleBufferAllocator.this, buf.capacity()); this.buf = buf; buf.order(ByteOrder.BIG_ENDIAN); } protected SimpleBuffer(SimpleBuffer parent, ByteBuffer buf) { super(parent); this.buf = buf; }
看到了吧,底层仍是用的NIO中的ByteBuffer。至于怎么实现AutoExpand这样的方法,我以为不是源码的重点,这些都是算法上的事情,若是你不关注算法,能够稍稍看看便可,并且好多都是native的实现,也看不到。而我这边主要关注的仍是他们之间的结构。
上图左边的路走通了,咱们来走右边的路,右边主要看AbstractIoBuffer,他是IoBuffer的具体实现,可是它也是一个抽象类,也要被其余类继承,用于扩展。AbstractIoBuffer中,大多类都是final的。并且这里面主要的实现都是在处理limit/position/mark/capacity这之间的关系。而CachedBufferAllocator主要用于实现IoBuffer中自动扩展AutoExpand和收缩: that caches the buffers which are likely to be reused during auto-expansion of the buffers.
----------------------------------------------------------最后,咱们将上面的叙述用一个删减版的代码来模拟一下,这样有助于理解代码的结构,之后遇到相似的状况就能够相似的处理,我更但愿,能在分析完全部源码以后,就能呈现一个相似的框架出来,不过这个真的只是想一想,毕竟没那么多时间,若是你有时间,能够试着去阉割一下mina。
首先是IoBuffer:
package org.apache.mina.core.rewrite.buffer; /** * IoBuffer * * @author ChenHui * */ public abstract class IoBuffer { private static IoBufferAllocator allocator=new SimpleBufferAllocator(); private static boolean direct; protected IoBuffer() { // do nothing } public static IoBuffer allocate(int capacity) { return allocator.allocate(capacity, direct); } public static IoBuffer wrap(byte[] byteArray, int offset, int length){ //TODO return null; } public abstract IoBuffer get(); public abstract IoBuffer put(byte b); public abstract boolean other(); }而后是他的继承:
package org.apache.mina.core.rewrite.buffer; import java.nio.ByteBuffer; /** * * @author ChenHui * */ public abstract class AbstractIoBuffer extends IoBuffer{ protected AbstractIoBuffer(ByteBuffer buffer){ //TODO } @Override public IoBuffer get() { // TODO Auto-generated method stub return null; } @Override public IoBuffer put(byte b) { // TODO Auto-generated method stub return null; } }allocator:
package org.apache.mina.core.rewrite.buffer; import java.nio.ByteBuffer; /** * * @author ChenHui * */ public interface IoBufferAllocator { IoBuffer allocate(int capacity, boolean direct); IoBuffer wrap(ByteBuffer nioBuffer); ByteBuffer allocateNioBuffer(int capacity, boolean direct); void dispose(); }allocator的实现:
package org.apache.mina.core.rewrite.buffer; import java.nio.ByteBuffer; /** * * @author ChenHui * */ public class SimpleBufferAllocator implements IoBufferAllocator{ @Override public IoBuffer allocate(int capacity, boolean direct) { return wrap(allocateNioBuffer(capacity, direct)); } @Override public IoBuffer wrap(ByteBuffer nioBuffer) { return new SimpleBuffer(nioBuffer); } @Override public ByteBuffer allocateNioBuffer(int capacity, boolean direct) { ByteBuffer nioBuffer; if (direct) { nioBuffer = ByteBuffer.allocateDirect(capacity); } else { nioBuffer = ByteBuffer.allocate(capacity); } return nioBuffer; } @Override public void dispose() { // TODO Auto-generated method stub } private class SimpleBuffer extends AbstractIoBuffer{ @SuppressWarnings("unused") ByteBuffer buffer; protected SimpleBuffer(ByteBuffer buffer){ super(buffer); this.buffer=buffer; } @Override public boolean other() { // TODO Auto-generated method stub return false; } /**这里重写是为了打印方便*/ @Override public String toString() { System.out.println(buffer); return super.toString(); } } }最后是测试类和测试结果:
package org.apache.mina.core.rewrite.buffer; public class Test { public static void main(String[] args) { IoBuffer buffer=IoBuffer.allocate(1024); System.out.println(buffer); } }控制台输出:
java.nio.HeapByteBuffer[pos=0 lim=1024 cap=1024] org.apache.mina.core.rewrite.buffer.SimpleBufferAllocator$SimpleBuffer@1da12fc0-------------------------------------------------------------------
后面一篇应该会将service,就是mina中实现链接的部分,后面的更新速度可能会慢点儿,到后面愈来愈复杂了,我得想一想怎么写才能写的号。最近在弄kafka,其实我还想写点儿kafka的东西,但是真的没有时间,kafka部分等我把分布式的弄完了再发点儿心得上来。你们将就着看吧。谢谢。
--------------------------------------------------------------------
转个面试题,北京一家作视频公司的算法题:《一道面试题》, @ppdep 已经有答案了。这题的第二问仍是颇有挑战的,你们能够去看看。