您好,登錄后才能下訂單哦!
這篇文章主要介紹“netty handler的執行順序是什么”,在日常操作中,相信很多人在netty handler的執行順序是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”netty handler的執行順序是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
handler的概念,讓我想到了其他的一些東西,就好像servlet當中的filter,spring當中的interceptor。 在handler當中,能夠完成各種各樣的工作,協議流的編解碼、特殊信息的攔截、請求數量的統計等等,或者可以這樣說,所有的業務層面的東西,都需要在handler當中來完成。
我會按照上行和下行兩類來分析handler的執行順序,今天先來下行的。
按照我最初的想象,所有的handler應該都是同一類東西,那么我們業務執行的方法,也就是我們繼承netty提供的父類之后,Override的方法,應該是同一個,可是我實際使用當中發現不是這么回事,有時候是一個decode方法,有時候是一個messageReceived方法,這是什么道理。基于這個困惑,才會有了今天的這篇文章。
首先是一個stacktrace的圖。
ProtocolAnaDecoder是我自己寫的一個協議解析類,繼承自 ByteToMessageDecoder ,在這個類里面依次調用了3個方法,channelRead(),callDecode(),decode()。這其中decode,是我們自己實現的,其他2個方法來自父類。
再看另一個圖。
NettyServerHandler繼承自SimpleChannelInboundHandler,這里依次調用了channelRead(),messageReceived()這樣2個方法。
到此為止基本就解決了我的第一個疑惑,最初都來自channelRead。那么這個 channelRead 雖然在各種handler當中都有實現,但是它的最初的定義來自ChannelHandler,這是一個interface。而它的實現ChannelHandlerAdapter,基本可以看做netty當中所有handler的老祖宗。(這里之所以要說基本,是因為有2個web相關的handler interface,直接繼承了 ChannelHandler,但這個不是我們今天討論的重點)
繼續,就該是ChannelHandlerInvokerUtil.invokeChannelReadNow,看代碼吧。
public static void invokeChannelReadNow(final ChannelHandlerContext ctx, final Object msg) {
try {
ctx.handler().channelRead(ctx, msg);
} catch (Throwable t) {
notifyHandlerException(ctx, t);
}
}
清楚明白,很好理解。
然后是DefaultChannelHandlerInvoker.invokeChannelRead,代碼如下:
@Override
public void invokeChannelRead(final ChannelHandlerContext ctx, final Object msg) {
if (msg == null) {
throw new NullPointerException("msg");
}
if (executor.inEventLoop()) {
invokeChannelReadNow(ctx, msg);
} else {
safeExecuteInbound(new Runnable() {
@Override
public void run() {
invokeChannelReadNow(ctx, msg);
}
}, msg);
}
}
executor.inEventLoop() ,當前channel的 executor 是否處于時間循環當中,好吧,到目前為止,我也不知道什么時候會走到else里面去,這里只好留待以后再去搞搞清楚了。
再往前走,DefaultChannelHandlerContext.fireChannelRead,代碼如下:
public ChannelHandlerContext fireChannelRead(Object msg) {
DefaultChannelHandlerContext next = findContextInbound(MASK_CHANNEL_READ);
next.invoker.invokeChannelRead(next, msg);
return this;
}
handler的依次執行就在這里面體現了。
繼續,DefaultChannelPipeline.fireChannelRead,代碼如下:
public ChannelPipeline fireChannelRead(Object msg) {
head.fireChannelRead(msg);
return this;
}
好了,如果沒記錯的話,我們最初聲明一個netty的時候,就是把一系列的handler加到了channel pipeline當中。那么這一系列的handler在pipeline當中是如何保存的呢。我首先先看一下 DefaultChannelPipeline 的構造函數:
public DefaultChannelPipeline(AbstractChannel channel) {
if (channel == null) {
throw new NullPointerException("channel");
}
this.channel = channel;
TailHandler tailHandler = new TailHandler();
tail = new DefaultChannelHandlerContext(this, null, generateName(tailHandler), tailHandler);
HeadHandler headHandler = new HeadHandler(channel.unsafe());
head = new DefaultChannelHandlerContext(this, null, generateName(headHandler), headHandler);
head.next = tail;
tail.prev = head;
}
首先生命了一個tail和一個head,然后把這2個對象構成了一個雙向鏈表。
再看一下addlast方法:
private void addLast0(final String name, DefaultChannelHandlerContext newCtx) {
checkMultiplicity(newCtx);
DefaultChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
name2ctx.put(name, newCtx);
callHandlerAdded(newCtx);
}
很清楚,在鏈表當中插入一個元素。再對照一下前面的代碼,首先從head開始,但它并不完成實際工作,直接取它的next來執行,之后依次便利鏈表。
到此,關于“netty handler的執行順序是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。