天天看點

Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

概述

一個問題
Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

編碼器實作了

ChannelOutboundHandler

,并将出站資料從 一種格式轉換為另一種格式,和我們方才學習的解碼器的功能正好相反。Netty 提供了一組類, 用于幫助你編寫具有以下功能的編碼器:

  • 将消息編碼為位元組
  • 将消息編碼為消息

    我們将首先從抽象基類 MessageToByteEncoder 開始來對這些類進行考察

1 抽象類 MessageToByteEncoder

Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

解碼器通常需要在

Channel

關閉之後産生最後一個消息(是以也就有了 

decodeLast()

方法)

這顯然不适于編碼器的場景——在連接配接被關閉之後仍然産生一個消息是毫無意義的

1.1 ShortToByteEncoder

其接受一

Short

 型執行個體作為消息,編碼為

Short

的原子類型值,并寫入

ByteBuf

,随後轉發給

ChannelPipeline

中的下一個 

ChannelOutboundHandler

每個傳出的 Short 值都将會占用 ByteBuf 中的 2 位元組

Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的
Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

1.2 Encoder

Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

Netty 提供了一些專門化的 

MessageToByteEncoder

,可基于此實作自己的編碼器

WebSocket08FrameEncoder

類提供了一個很好的執行個體

Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

2 抽象類 MessageToMessageEncoder

你已經看到了如何将入站資料從一種消息格式解碼為另一種

為了完善這幅圖,将展示 對于出站資料将如何從一種消息編碼為另一種。

MessageToMessageEncoder

類的 

encode()

方法提供了這種能力

Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

為了示範,使用

IntegerToStringEncoder

擴充了

MessageToMessageEncoder

  • 編碼器将每個出站 Integer 的 String 表示添加到了該 List 中
Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的
Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

關于有趣的 MessageToMessageEncoder 的專業用法,請檢視 

io.netty.handler. codec.protobuf.ProtobufEncoder

類,它處理了由 Google 的 Protocol Buffers 規範所定義 的資料格式。

一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

writeAndFlush

  • 從tail節點開始往前傳播
  • 逐個調用channelHandler#write
  • 逐個調用channelHandler#flush

java對象編碼過程

write:寫隊列

flush:重新整理寫隊列

writeAndFlush: 寫隊列并重新整理

pipeline中的标準連結清單結構

Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

資料從head節點流入,先拆包,然後解碼成業務對象,最後經過業務Handler處理,調用write,将結果對象寫出去

而寫的過程先通過tail節點,然後通過encoder節點将對象編碼成ByteBuf,最後将該ByteBuf對象傳遞到head節點,調用底層的Unsafe寫到JDK底層管道

Java對象編碼過程

為什麼我們在pipeline中添加了encoder節點,java對象就轉換成netty可以處理的ByteBuf,寫到管道裡?

我們先看下調用write的code

Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

業務處理器接受到請求之後,做一些業務處理,傳回一個

user

  • 然後,user在pipeline中傳遞
Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的
Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的
Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的
Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

情形一

Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的
Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

情形二

Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的
Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的
Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的
Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

handler 如果不覆寫 flush 方法,就會一直向前傳遞直到 head 節點

Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

落到 

Encoder

節點,下面是 

Encoder

 的處理流程

Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的

按照簡單自定義協定,将Java對象 User 寫到傳入的參數 out中,這個out到底是什麼?

需知

User

對象,從

BizHandler

傳入到

MessageToByteEncoder

時,首先傳到

write

Netty 源碼深度解析(九) - 編碼(上)概述1 抽象類 MessageToByteEncoder2 抽象類 MessageToMessageEncoder一個java對象最後是如何轉變成位元組流,寫到socket緩沖區中去的