上一篇《總體解讀》的延續。。 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 已經有答案了。這題的第二問仍是頗有挑戰的,你們能夠去看看。