Mina源碼閱讀筆記(二)- IoBuffer的封裝

上一篇《總體解讀》的延續。。 java

在閱讀IoBuffer源碼以前,咱們先看MinaIoBuffer的描述:A byte buffer used by MINA applications. This is a replacement for ByteBuffer. 這是一個對ByteBufferreplacement,一樣是用做緩衝區,作內容的切換和承載的容器,爲何要用從新封裝ByteBufferMINA是這麼給出解釋的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中能夠直接putget 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,這塊內存的開闢就比較麻煩了,好多都是採用了Bitnative的方法: ide

public static ByteBuffer allocateDirect(int capacity) {
        return new DirectByteBuffer(capacity);
    }

除了構造以外,剩下的主要是對數據的操做方法,wrapgetput,下面的圖沒有截全,還有好多方法: 工具

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畫了。囧一個,你們有好那種能夠一鍵生成的工具推薦一下,我以前用的是JUDEVisio。上圖畫出了IoBuffer中幾個重要類之間的關係,兩個內部類均繼承了AbstractIoBufferAbstractIoBufferIoBufferWrapper均實現了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 已經有答案了。這題的第二問仍是頗有挑戰的,你們能夠去看看。

相關文章
相關標籤/搜索