共計 2426 個字符,預計需要花費 7 分鐘才能閱讀完成。
本篇內容主要講解“handler 的執行順序是怎么樣的”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓丸趣 TV 小編來帶大家學習“handler 的執行順序是怎么樣的”吧!
為了說明這個問題我們增加了 2 個 encoder,分別是 MavlinkMsg2BytesEncoder 和 FixLengthEncoder,作用分別是將一個協議對象轉化為 byte 數組,另一個是為了客戶端解析的方便,增加了一個定長的設置。
還是按照老方法,設置斷點,然后查看其調用順序。
NettyServerHandler.messageReceived 是我們接收下行消息的終點,我們直接在這里來執行消息的返回。
首先進入 NioSocketChannel.write 方法,下面是代碼
@Override
public ChannelFuture write(Object msg) {
return pipeline.write(msg);
}
write 方法定義在 AbstractChannel 當中,是 netty 當中所有的 channel 類的祖先。
在這個方法當中,開始執行依次執行 pipeline 當中的各個 handler
下面是 DefaultChannelPipeline.write 方法
@Override
public ChannelFuture write(Object msg) {
return tail.write(msg);
}
如果沒有記錯的話,下行的過程當中,是從 head.fireChannelRead 開始的,而在上行的過程當中,是從 tail 開始的,而實際上,head 和 tail 是 pipeline 在初始化的時候默認生成的雙向鏈表的頭尾節點,他們并不完成任何實際工作。這里從 tail 開是上行的過程,應該說是非常符合邏輯的。
下一步我們看 DefaultChannelHandlerContext.write 方法
@Override
public ChannelFuture write(Object msg, ChannelPromise promise) {
DefaultChannelHandlerContext next = findContextOutbound(MASK_WRITE);
next.invoker.invokeWrite(next, msg, promise);
return promise;
}
這里也是之前我們分析過的代碼,查找雙向鏈表當中 prev 節點。
之后是 ChannelHandlerInvokerUtil.invokeWriteNow 方法,
public static void invokeWriteNow(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
try {
ctx.handler().write(ctx, msg, promise);
} catch (Throwable t) {
notifyOutboundHandlerException(t, promise);
}
}
再然后是 MessageToByteEncoder.write 方法,
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
ByteBuf buf = null;
try {
if (acceptOutboundMessage(msg)) {
@SuppressWarnings(unchecked)
I cast = (I) msg;
if (preferDirect) {
buf = ctx.alloc().ioBuffer();
} else {
buf = ctx.alloc().heapBuffer();
}
try {
encode(ctx, cast, buf);
} finally {
ReferenceCountUtil.release(cast);
}
if (buf.isReadable()) {
ctx.write(buf, promise);
} else {
buf.release();
ctx.write(Unpooled.EMPTY_BUFFER, promise);
}
buf = null;
} else {
ctx.write(msg, promise);
}
} catch (EncoderException e) {
throw e;
} catch (Throwable e) {
throw new EncoderException(e);
} finally {
if (buf != null) {
buf.release();
}
}
}
這里分配一個動態緩沖區,然后調用 encoder 方法。
if (preferDirect) {
buf = ctx.alloc().ioBuffer();
} else {
buf = ctx.alloc().heapBuffer();
}
請注意這段代碼,這里的概念是指,當前緩沖區的分配是從系統 io 當中來分配,還是從 jvm 的堆當中來分配,2 種方式各有利弊,將來我們會專門介紹這個問題。
在最后就是我們的 encode 方法了。
protected void encode(ChannelHandlerContext ctx, MAVLinkMessage msg, ByteBuf out) throws Exception {
MAVLinkPacket packet = msg.pack();
byte[] buf = packet.encodePacket();
out.writeBytes(buf);
}
而后續的 encoder 的調用過程基本跟前面大同小異。這里就不再贅述了。
到此,相信大家對“handler 的執行順序是怎么樣的”有了更深的了解,不妨來實際操作一番吧!這里是丸趣 TV 網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!