[英]Decoder, Encoder, ServerHandler pipeline in netty
查看文檔,它說:
https://netty.io/4.0/api/io/netty/channel/ChannelPipeline.html
用戶應該在管道中有一個或多個 ChannelHandler 來接收 I/O 事件(例如讀取)和請求 I/O 操作(例如寫入和關閉)。 例如,典型的服務器將在每個通道的管道中具有以下處理程序,但您的里程可能會因協議和業務邏輯的復雜性和特征而異:
協議解碼器 - 將二進制數據(例如 ByteBuf)轉換為 Java 對象。 協議編碼器 - 將 Java 對象轉換為二進制數據。
業務邏輯處理程序 - 執行實際的業務邏輯(例如數據庫訪問)。 它可以表示為如下示例所示: static final EventExecutorGroup group = new DefaultEventExecutorGroup(16); ...
ChannelPipeline 管道 = ch.pipeline();
pipeline.addLast("decoder", new MyProtocolDecoder());
pipeline.addLast("encoder", new MyProtocolEncoder());
// 告訴管道在與 I/O 線程不同的線程中 // 運行 MyBusinessLogicHandler 的事件處理程序方法,以便 I/O 線程不會被耗時的任務阻塞 //。 // 如果您的業務邏輯是完全異步的或很快完成,您就不需要 // 指定一個組。
pipeline.addLast(group, "handler", new MyBusinessLogicHandler());
在 Github 上的許多示例中,我看到了相同的模式。 我想知道是否有人可以解釋為什么 businessHandler 不在解碼器和編碼器之間。 我認為你會得到你的 POJO,然后在業務處理程序中處理它,然后對它進行編碼。
由於調用處理程序的順序,解碼器和編碼器通常位於管道的開頭。 對於傳入的數據,它是自下而上的,而傳出的數據是自上而下的。
例如
pipeline.addLast(new MyEncoder());
pipeline.addLast(new MyDecoder());
pipeline.addLast(new MyBusiness());
在這種情況下,傳入數據的調用順序是:MyDecoder(將數據轉換為POJO)-> MyBusiness(傳入流不調用編碼器),傳出數據:MyBusiness -> MyEncoder(傳出流不調用解碼器) .
如果您在業務處理程序(實際上是解碼器之后的 POJO)中接收到傳入流並將其寫回,則看起來 MyBusiness 位於編碼器和解碼器之間,因為數據正在返回編碼器。
當然,業務處理程序介於解碼器和編碼器之間。以 Factorial 示例為例。
public void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
if (sslCtx != null) {
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
}
// Enable stream compression (you can remove these two if unnecessary)
pipeline.addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
pipeline.addLast(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
// Add the number codec first,
pipeline.addLast(new BigIntegerDecoder());
pipeline.addLast(new NumberEncoder());
// and then business logic.
// Please note we create a handler for every new channel
// because it has stateful properties.
pipeline.addLast(new FactorialServerHandler());
}`
在initChannel
的函數中initChannel
pipeline先添加encoder和decoder,最后添加handler。 執行流程實際上是按解碼器、處理程序和編碼器排序的。 解碼器、處理程序和編碼器等處理程序實際上存儲在AbstractChannelHandlerContext
類中。 Netty 中有一個AbstractChannelHandlerContext
的鏈表。 列表的排列方式是decoder context
--> handler context
--> encoder context
,執行是一樣的!
事實上,如果你在你的服務器中添加ctx.channel().writeAndFlush()
,並且你編寫ctx.channel().writeAndFlush()
或ctx.pipeline().writeAndFlush()
,那么編碼器將被調用. 在這種情況下是 bc,它將從尾部開始尋找上一個 outboundChannel。 但是,如果您編寫ctx.writeAndFlush()
,它將從 businessHandler 的位置查找上一個 outboundChannel。 在AbstractChannelHandlerContext的findContextOutbound()
的第一行加斷點,就搞定了。
private AbstractChannelHandlerContext findContextOutbound(int mask) {
AbstractChannelHandlerContext ctx = this;
EventExecutor currentExecutor = executor();
do {
ctx = ctx.prev;
} while (skipContext(ctx, currentExecutor, mask, MASK_ONLY_OUTBOUND));
return ctx;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.