天天看點

深入Jetty源碼之Buffer

在jetty中buffer是對java中stream io中的buffer和nio中的buffer的抽象表示,它主要用于緩存連接配接中讀取和寫入的資料。在jetty中,對每個連接配接使用buffer從其inputstream中讀取位元組資料,或将處理後的響應位元組寫入outputstream中,進而jetty其他子產品在處理請求和響應資料時直接和buffer打交道,而不需要關注底層io流。 

jetty中buffer接口定義如下:

public interface buffer extends cloneable {

    // 基于buffer主要用于向目前連接配接讀寫資料,因而它定義了兩個核心的方法:readfrom和writeto。其中readfrom方法從inputstream中讀取位元組資料,writeto方法将響應位元組寫入outputstream中,即向connection中讀取和寫入資料,寫完後清理目前buffer。

    int readfrom(inputstream in, int max) throws ioexception;

    void writeto(outputstream out) throws ioexception;

    // 在buffer從inputstream(connection)中讀取資料後,buffer接口還提供了很多不同的方法用于從buffer中讀取或寫入位元組資料。

    // jetty中的buffer是一個fifo的位元組隊列,它的設計類似nio中buffer的設計:每次get操作都從getindex開始,并且getindex會向前移動讀取的位元組數的長度;每次的peek操作也getindex開始,但是peek操作不會使getindex向前移動;每次put操作都從putindex開始,并且putindex會向前移動寫入的位元組數的長度;每次poke操作也會從putindex開始,但是poke操作不會使putindex向前移動;mark操作會以getindex作為基準設定markindex的值,進而在reset時會将getindex重置到之前mark過的位置;capacity表示該buffer最多可存儲的位元組數,而length表示從getindex到putindex還存在的位元組數。并且buffer永遠保證以下關系總是成立:markindex<=getindex<=putindex<=capacity

    byte get();

    int get(byte[] b, int offset, int length);

    buffer get(int length);

    int getindex();

    void mark();

    void mark(int offset);

    int markindex();

    byte peek();

    byte peek(int index);

    buffer peek(int index, int length);

    int peek(int index, byte[] b, int offset, int length);

    int poke(int index, buffer src);

    void poke(int index, byte b);

    int poke(int index, byte b[], int offset, int length);

    int put(buffer src);

    void put(byte b);

    int put(byte[] b,int offset, int length);

    int put(byte[] b);

    int putindex();

    int length();

    void clear();

    void reset();

    void setgetindex(int newstart);

    void setmarkindex(int newmark);

    void setputindex(int newlimit);

    // 一個buffer還有獨立的兩種狀态:access級别和volatile。

access級别有:immutable,表示目前buffer所有的index和内容都不能被改變;readonly,表示目前buffer是隻讀的,即getindex和markindex可以被改變,而putindex以及buffer内容不可以;readwrite,表示所有的index以及buffer的内容可以被改變。

volatile狀态表示目前buffer是否會通過其他路徑被修改,預設情況下,bytearraybuffer、directniobuffer等是non_volatile狀态,而view是volatile狀态(除非view内部的buffer是immutable)。volatile的狀态感覺不是一個比較嚴謹的概念,比如對一個view它是volatile的,但是在這種情況下,它内部包裝的buffer應該也變成volatile狀态,并且在所有的view被回收後,其内部包裝的buffer應該重新變成non_volatile狀态。要實作這種嚴謹邏輯應該是可以做的到的,隻是會比較麻煩,而且貌似也沒必要,因而jetty并沒有嘗試着去這樣做。

    // 傳回包含目前buffer從getindex到putindex内容的buffer,并且傳回的buffer不可以被其他路徑修改。如果目前buffer是non_volatile,則直接傳回目前buffer(這個實作是不嚴謹的,因為在這種情況下,其實有兩個buffer執行個體可以修改同一份資料),否則,克隆一個新的buffer,這樣對新的buffer的修改不會影響原buffer的内容。

    buffer asnonvolatilebuffer();

    // 傳回一個隻讀的buffer(view),該隻讀的buffer的讀取不會影響原來buffer的index。

    buffer asreadonlybuffer();

    // 拷貝一個不可修改的bytebuffer。

    buffer asimmutablebuffer();

    // 傳回一個可修改的buffer,并且對傳回的buffer的内容修改會影響原有的buffer。

    buffer asmutablebuffer();

    // 目前buffer是否不可被修改,即buffer内容和所有index都不能被修改。

    boolean isimmutable();

    // 目前buffer是否是隻讀的。

    boolean isreadonly();

    // 是否目前buffer内容可以通過其他路徑被修改,比如view一般情況下是volatile狀态(除非view内部的buffer是immutable)。

   boolean isvolatile();

    // 除了以上的操作,buffer還提供了一些其他用于操作buffer内部位元組的方法:

    //如果内部使用位元組數組表示,傳回該位元組數組,否則,傳回null。

    byte[] array();

    // 擷取從getindex到putindex的位元組數組,其長度為length。

    byte[] asarray();

    // 如果目前buffer是對另一個buffer的包裝,則傳回内部被包裝的buffer執行個體,否則傳回目前buffer本身。

    buffer buffer();

    int capacity();

    // 傳回目前buffer剩餘的空間,即capacity-putindex。

    int space();

    // 清除buffer内容,即設定getindex和putindex為0,以及markindex為-1。

    // 整理buffer内容,即将markindex >= 0 ? min(getindex, markindex) : getindex到putindex的内容移動到buffer的起始位置,同時修改相應的getindex、markindex、putindex。

    void compact();

    // 目前buffer是否有可用位元組,即是否putindex>getindex。

    boolean hascontent();

    // 跳過n個位元組,即getindex增加min(remaining(), n)的值。

    int skip(int n);

    // 切割出目前buffer從getindex到putindex的view,一般來說它是volatile的(除非它是immutable類型的buffer)。

    buffer slice();

    // 切割出目前buffer從markindex到putindex的view,一般來說它是volatile的(除非它是immutable類型的buffer)。

    buffer slicefrommark();

    buffer slicefrommark(int length);

    // 傳回包含目前buffer狀态和内容的字元串。

    string todetailstring();

    boolean equalsignorecase(buffer buffer);

 }

深入Jetty源碼之Buffer

abstractbuffer:

所有buffer的基類,是對buffer接口的基本實作。

bytebuffer:

它繼承自abstractbuffer主要的非nio的buffer實作,内部使用位元組數組做緩存,直接讀inputstream和寫outputstream。

directniobuffer:

它實作了niobuffer接口,繼承自abstractbuffer,内部使用direct的bytebuffer做緩存,使用readablebytechannel和writablebytechannel分别對inputstream(readfrom傳入)和outputstream(writeto傳入)包裝,并在這兩個方法中使用包裝後的channel讀寫資料。

indirectniobuffer:

它繼承自bytebuffer,内部使用非direct的bytebuffer做緩存,并且它也直接對inputstream和outputstream讀寫。

randomaccessfilebuffer:

它繼承自abstractbuffer,内部使用randomaccessfile做緩存。

view:

它繼承自abstractbuffer,内部使用另一個buffer作為緩存,并且對非immutable的buffer,很多時候,它是volatile。view如其名,它是對内部buffer的視圖,對view内容以及index的修改會影響内部buffer中相應的值。

buffers是buffer的抽象工廠,它用于建立header的buffer和body的buffer,并且可以根據給定的size獲得相應的buffer執行個體,在buffer使用完成後,還可以通過returnbuffer方法将它歸還個buffers以複用。在建立buffers子類時,可以将指定header和body各自buffer的類型,進而在内部建立相應buffer時會建立相應類型的buffer,支援的buffer類型有:byte_array、direct、indirect。

jetty中有兩個buffers的實作:pooledbuffers和threadlocalbuffers。

pooledbuffers使用concurrentlinkedqueue建構各自的header、body、other類型的buffer池,它有一個maxsize值用于控制該buffers中包含的所有類型的buffer的總數。 threadlocalbuffers将header、body、other類型的buffer儲存在threadlocal中。

jetty還提供了buffersfactory用于建立不同類型的buffers:通過在參數中maxsize是否大于等于0以決定是使用pooledbuffers還是threadlocalbuffers。 

jetty還為buffer提供了兩個特殊的類:buffercache和bufferdatecache。

buffercache

用于存儲一個可以使用存儲的string值、索引值等擷取相應的buffer執行個體,主要用于httpheaders、httpmethods等一些預定義的值。

bufferdatecache

繼承自datecache,它存儲了上一次使用一個long類型的date值格式化出的buffer執行個體,進而實作部分複用(複用在同一秒得到的request請求時建立的buffer,因為時間也隻能在這種情況下被複用,因而才會有這樣的實作),在request類中使用。