您好,登錄后才能下訂單哦!
這篇文章主要介紹“netty handler的執(zhí)行順序是什么”,在日常操作中,相信很多人在netty handler的執(zhí)行順序是什么問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”netty handler的執(zhí)行順序是什么”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
handler的概念,讓我想到了其他的一些東西,就好像servlet當(dāng)中的filter,spring當(dāng)中的interceptor。 在handler當(dāng)中,能夠完成各種各樣的工作,協(xié)議流的編解碼、特殊信息的攔截、請(qǐng)求數(shù)量的統(tǒng)計(jì)等等,或者可以這樣說(shuō),所有的業(yè)務(wù)層面的東西,都需要在handler當(dāng)中來(lái)完成。
我會(huì)按照上行和下行兩類來(lái)分析handler的執(zhí)行順序,今天先來(lái)下行的。
按照我最初的想象,所有的handler應(yīng)該都是同一類東西,那么我們業(yè)務(wù)執(zhí)行的方法,也就是我們繼承netty提供的父類之后,Override的方法,應(yīng)該是同一個(gè),可是我實(shí)際使用當(dāng)中發(fā)現(xiàn)不是這么回事,有時(shí)候是一個(gè)decode方法,有時(shí)候是一個(gè)messageReceived方法,這是什么道理?;谶@個(gè)困惑,才會(huì)有了今天的這篇文章。
首先是一個(gè)stacktrace的圖。
ProtocolAnaDecoder是我自己寫(xiě)的一個(gè)協(xié)議解析類,繼承自 ByteToMessageDecoder ,在這個(gè)類里面依次調(diào)用了3個(gè)方法,channelRead(),callDecode(),decode()。這其中decode,是我們自己實(shí)現(xiàn)的,其他2個(gè)方法來(lái)自父類。
再看另一個(gè)圖。
NettyServerHandler繼承自SimpleChannelInboundHandler,這里依次調(diào)用了channelRead(),messageReceived()這樣2個(gè)方法。
到此為止基本就解決了我的第一個(gè)疑惑,最初都來(lái)自channelRead。那么這個(gè) channelRead 雖然在各種handler當(dāng)中都有實(shí)現(xiàn),但是它的最初的定義來(lái)自ChannelHandler,這是一個(gè)interface。而它的實(shí)現(xiàn)ChannelHandlerAdapter,基本可以看做netty當(dāng)中所有handler的老祖宗。(這里之所以要說(shuō)基本,是因?yàn)橛?個(gè)web相關(guān)的handler interface,直接繼承了 ChannelHandler,但這個(gè)不是我們今天討論的重點(diǎn))
繼續(xù),就該是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() ,當(dāng)前channel的 executor 是否處于時(shí)間循環(huán)當(dāng)中,好吧,到目前為止,我也不知道什么時(shí)候會(huì)走到else里面去,這里只好留待以后再去搞搞清楚了。
再往前走,DefaultChannelHandlerContext.fireChannelRead,代碼如下:
public ChannelHandlerContext fireChannelRead(Object msg) {
DefaultChannelHandlerContext next = findContextInbound(MASK_CHANNEL_READ);
next.invoker.invokeChannelRead(next, msg);
return this;
}
handler的依次執(zhí)行就在這里面體現(xiàn)了。
繼續(xù),DefaultChannelPipeline.fireChannelRead,代碼如下:
public ChannelPipeline fireChannelRead(Object msg) {
head.fireChannelRead(msg);
return this;
}
好了,如果沒(méi)記錯(cuò)的話,我們最初聲明一個(gè)netty的時(shí)候,就是把一系列的handler加到了channel pipeline當(dāng)中。那么這一系列的handler在pipeline當(dāng)中是如何保存的呢。我首先先看一下 DefaultChannelPipeline 的構(gòu)造函數(shù):
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;
}
首先生命了一個(gè)tail和一個(gè)head,然后把這2個(gè)對(duì)象構(gòu)成了一個(gè)雙向鏈表。
再看一下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);
}
很清楚,在鏈表當(dāng)中插入一個(gè)元素。再對(duì)照一下前面的代碼,首先從head開(kāi)始,但它并不完成實(shí)際工作,直接取它的next來(lái)執(zhí)行,之后依次便利鏈表。
到此,關(guān)于“netty handler的執(zhí)行順序是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。