天天看點

Netty 源碼深度解析(九) - 編碼(中)

1. 判斷目前Handelr是否能處理寫入的消息(比對對象)

Netty 源碼深度解析(九) - 編碼(中)
Netty 源碼深度解析(九) - 編碼(中)
Netty 源碼深度解析(九) - 編碼(中)

判斷該對象是否是該類型參數比對器執行個體可比對到的類型

Netty 源碼深度解析(九) - 編碼(中)
Netty 源碼深度解析(九) - 編碼(中)

2 配置設定記憶體

Netty 源碼深度解析(九) - 編碼(中)
Netty 源碼深度解析(九) - 編碼(中)

3 編碼實作

  • 調用

    encode

    ,這裡就調回到

    Encoder

    這個

    Handler

Netty 源碼深度解析(九) - 編碼(中)
  • 其為抽象方法,是以自定義實作類實作編碼方法
Netty 源碼深度解析(九) - 編碼(中)
Netty 源碼深度解析(九) - 編碼(中)

4 釋放對象

  • 既然自定義Java對象轉換成

    ByteBuf

    了,那麼這個對象就已經無用,釋放掉 (當傳入的

    msg

    類型是

    ByteBuf

    時,就不需要自己手動釋放了)
Netty 源碼深度解析(九) - 編碼(中)
Netty 源碼深度解析(九) - 編碼(中)

5 傳播資料

//112 如果buf中寫入了資料,就把buf傳到下一個節點,直到 header 節點

Netty 源碼深度解析(九) - 編碼(中)

6 釋放記憶體

//115 否則,釋放buf,将空資料傳到下一個節點

// 120 如果目前節點不能處理傳入的對象,直接扔給下一個節點處理

// 127 當buf在pipeline中處理完之後,釋放

Netty 源碼深度解析(九) - 編碼(中)

Encoder處理傳入的Java對象

  • 判斷目前Handler是否能處理寫入的消息
  • 如果能處理,進入下面的流程
  • 否則,直接扔給下一個節點處理
  • 将對象強制轉換成Encoder 可以處理的 Response對象
  • 配置設定一個ByteBuf
  • 調用encoder,即進入到 Encoder 的 encode方法,該方法是使用者代碼,使用者将資料寫入ByteBuf
  • 既然自定義Java對象轉換成ByteBuf了,那麼這個對象就已經無用了,釋放掉(當傳入的msg類型是ByteBuf時,無需自己手動釋放)
  • 如果buf中寫入了資料,就把buf傳到下一個節點,否則,釋放buf,将空資料傳到下一個節點
  • 最後,當buf在pipeline中處理完之後,釋放節點

總結就是,

Encoder

節點配置設定一個

ByteBuf

,調用

encode

方法,将Java對象根據自定義協定寫入到ByteBuf,然後再把ByteBuf傳入到下一個節點,在我們的例子中,最終會傳入到head節點

public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    unsafe.write(msg, promise);
}
      

這裡的msg就是前面在Encoder節點中,載有java對象資料的自定義ByteBuf對象

write - 寫buffer隊列
Netty 源碼深度解析(九) - 編碼(中)

Netty 源碼深度解析(九) - 編碼(中)
Netty 源碼深度解析(九) - 編碼(中)
Netty 源碼深度解析(九) - 編碼(中)
Netty 源碼深度解析(九) - 編碼(中)
Netty 源碼深度解析(九) - 編碼(中)
Netty 源碼深度解析(九) - 編碼(中)
Netty 源碼深度解析(九) - 編碼(中)

以下過程分三步講解

Netty 源碼深度解析(九) - 編碼(中)

direct ByteBuf

Netty 源碼深度解析(九) - 編碼(中)
Netty 源碼深度解析(九) - 編碼(中)
  • 首先,調用

    assertEventLoop

    確定該方法的調用是在

    reactor

    線程中
  • 然後,調用

    filterOutboundMessage()

    ,将待寫入的對象過濾,把非

    ByteBuf

    對象和

    FileRegion

    過濾,把所有的非直接記憶體轉換成直接記憶體

    DirectBuffer

Netty 源碼深度解析(九) - 編碼(中)
Netty 源碼深度解析(九) - 編碼(中)

插入寫隊列

  • 接下來,估算出需要寫入的ByteBuf的size
Netty 源碼深度解析(九) - 編碼(中)
  • 最後,調用 ChannelOutboundBuffer 的addMessage(msg, size, promise) 方法,是以,接下來,我們需要重點看一下這個方法幹了什麼事情
Netty 源碼深度解析(九) - 編碼(中)

想要了解上面這段代碼,須掌握寫緩存中的幾個消息指針

Netty 源碼深度解析(九) - 編碼(中)

ChannelOutboundBuffer 裡面的資料結構是一個單連結清單結構,每個節點是一個 Entry,Entry 裡面包含了待寫出ByteBuf 以及消息回調 promise下面分别是

三個指針的作用

  • flushedEntry

表第一個被寫到OS Socket緩沖區中的節點

Netty 源碼深度解析(九) - 編碼(中)
  • unFlushedEntry

表第一個未被寫入到OS Socket緩沖區中的節點

Netty 源碼深度解析(九) - 編碼(中)
  • tailEntry

ChannelOutboundBuffer

緩沖區的最後一個節點

Netty 源碼深度解析(九) - 編碼(中)

圖解過程

  • 初次調用write 即 

    addMessage

     後
Netty 源碼深度解析(九) - 編碼(中)
  • 第二次調用 

    addMessage

Netty 源碼深度解析(九) - 編碼(中)
  • 第n次調用 

    addMessage

Netty 源碼深度解析(九) - 編碼(中)

可得,調用n次

addMessage

  • flushedEntry

    指針一直指向

    null

    ,表此時尚未有節點需寫到Socket緩沖區
  • unFushedEntry

    後有n個節點,表目前還有n個節點尚未寫到Socket緩沖區