日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

netty系列之:channelHandlerContext详解

發(fā)布時間:2024/2/28 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 netty系列之:channelHandlerContext详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 簡介
  • ChannelHandlerContext和它的應用
  • AbstractChannelHandlerContext
  • DefaultChannelHandlerContext
  • 總結(jié)

簡介

我們知道ChannelHandler有兩個非常重要的子接口,分別是ChannelOutboundHandler和ChannelInboundHandler,基本上這兩個handler接口定義了所有channel inbound和outbound的處理邏輯。

不管是ChannelHandler還是ChannelOutboundHandler和ChannelInboundHandler,幾乎他們中所有的方法都帶有一個ChannelHandlerContext參數(shù),那么這個ChannelHandlerContext到底是做什么用的呢?它和handler、channel有什么關(guān)系呢?

ChannelHandlerContext和它的應用

熟悉netty的朋友應該都接觸過ChannelHandlerContext,如果沒有的話,這里有一個簡單的handler的例子:

public class ChatServerHandler extends SimpleChannelInboundHandler<String> {@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {log.info("accepted channel: {}", ctx.channel());log.info("accepted channel parent: {}", ctx.channel().parent());// channel活躍ctx.write("Channel Active狀態(tài)!\r\n");ctx.flush();} }

這里的handler繼承了SimpleChannelInboundHandler,只需要實現(xiàn)對應的方法即可。這里實現(xiàn)的是channelActive方法,在channelActive方法中,傳入了一個ChannelHandlerContext參數(shù),我們可以通過使用ChannelHandlerContext來調(diào)用它的一些方法。

先來看一下ChannelHandlerContext的定義:

public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {

首先ChannelHandlerContext是一個AttributeMap,可以用來存儲多個數(shù)據(jù)。

然后ChannelHandlerContext繼承了ChannelInboundInvoker和ChannelOutboundInvoker,可以觸發(fā)inbound和outbound的一些方法。

除了繼承來的一些方法之外,ChannelHandlerContext還可以作為channel,handler和pipline的溝通橋梁,因為可以從ChannelHandlerContext中獲取到對應的channel,handler和pipline:

Channel channel(); ChannelHandler handler(); ChannelPipeline pipeline();

還要注意的是ChannelHandlerContext還返回一個EventExecutor,用來執(zhí)行特定的任務(wù):

EventExecutor executor();

接下來,我們具體看一下ChannelHandlerContext的實現(xiàn)。

AbstractChannelHandlerContext

AbstractChannelHandlerContext是ChannelHandlerContext的一個非常重要的實現(xiàn),雖然AbstractChannelHandlerContext是一個抽象類,但是它基本上實現(xiàn)了ChannelHandlerContext的所有功能。

首先看一下AbstractChannelHandlerContext的定義:

abstract class AbstractChannelHandlerContext implements ChannelHandlerContext, ResourceLeakHint

AbstractChannelHandlerContext是ChannelHandlerContext的一個具體實現(xiàn)。

通常來說一個handler對應一個ChannelHandlerContext,但是在一個程序中可能會有多于一個handler,那么如何在一個handler中獲取其他的handler呢?

在AbstractChannelHandlerContext中有兩個同樣是AbstractChannelHandlerContext類型的next和prev,從而使得多個AbstractChannelHandlerContext可以構(gòu)建一個雙向鏈表。從而可以在一個ChannelHandlerContext中,獲取其他的ChannelHandlerContext,從而獲得handler處理鏈。

volatile AbstractChannelHandlerContext next;volatile AbstractChannelHandlerContext prev;

AbstractChannelHandlerContext中的pipeline和executor都是通過構(gòu)造函數(shù)傳入的:

AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor,String name, Class<? extends ChannelHandler> handlerClass) {this.name = ObjectUtil.checkNotNull(name, "name");this.pipeline = pipeline;this.executor = executor;this.executionMask = mask(handlerClass);// Its ordered if its driven by the EventLoop or the given Executor is an instanceof OrderedEventExecutor.ordered = executor == null || executor instanceof OrderedEventExecutor;}

可能有朋友會有疑問了,ChannelHandlerContext中的channel和handler是如何得到的呢?

對于channel來說,是通過pipeline來獲取的:

public Channel channel() {return pipeline.channel();}

對于handler來說,在AbstractChannelHandlerContext中并沒有對其進行實現(xiàn),需要在繼承AbstractChannelHandlerContext的類中進行實現(xiàn)。

對于EventExecutor來說,可以通過構(gòu)造函數(shù)向AbstractChannelHandlerContext傳入一個新的EventExecutor,如果沒有傳入或者傳入為空的話,則會使用channel中自帶的EventLoop:

public EventExecutor executor() {if (executor == null) {return channel().eventLoop();} else {return executor;}}

因為EventLoop繼承自O(shè)rderedEventExecutor,所以它也是一個EventExecutor。

EventExecutor主要用來異步提交任務(wù)來執(zhí)行,事實上ChannelHandlerContext中幾乎所有來自于ChannelInboundInvoker和ChannelOutboundInvoker的方法都是通過EventExecutor來執(zhí)行的。

對于ChannelInboundInvoker來說,我們以方法fireChannelRegistered為例:

public ChannelHandlerContext fireChannelRegistered() {invokeChannelRegistered(findContextInbound(MASK_CHANNEL_REGISTERED));return this;}static void invokeChannelRegistered(final AbstractChannelHandlerContext next) {EventExecutor executor = next.executor();if (executor.inEventLoop()) {next.invokeChannelRegistered();} else {executor.execute(new Runnable() {@Overridepublic void run() {next.invokeChannelRegistered();}});}}

fireChannelRegistered調(diào)用了invokeChannelRegistered方法,invokeChannelRegistered則調(diào)用EventExecutor的execute方法,將真實的調(diào)用邏輯封裝在一個runnable類中執(zhí)行。

注意,在調(diào)用executor.execute方法之前有一個executor是否在eventLoop中的判斷。如果executor已經(jīng)在eventLoop中了,那么直接執(zhí)行任務(wù)即可,不需要啟用新的線程。

對于ChannelOutboundInvoker來說,我們以bind方法為例,看一下EventExecutor是怎么使用的:

public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {ObjectUtil.checkNotNull(localAddress, "localAddress");if (isNotValidPromise(promise, false)) {// cancelledreturn promise;}final AbstractChannelHandlerContext next = findContextOutbound(MASK_BIND);EventExecutor executor = next.executor();if (executor.inEventLoop()) {next.invokeBind(localAddress, promise);} else {safeExecute(executor, new Runnable() {@Overridepublic void run() {next.invokeBind(localAddress, promise);}}, promise, null, false);}return promise;}

可以看到執(zhí)行的邏輯和invokeChannelRegistered方法很類似,也是先判斷executor在不在eventLoop中,如果在的話直接執(zhí)行,如果不在則放在executor中執(zhí)行。

上面的兩個例子中都調(diào)用了next的相應方法,分別是next.invokeChannelRegistered和next.invokeBind。

我們知道ChannelHandlerContext只是一個封裝,它本身并沒有太多的業(yè)務(wù)邏輯,所以next調(diào)用的相應方法,實際上是Context中封裝的ChannelInboundHandler和ChannelOutboundHandler中的業(yè)務(wù)邏輯,如下所示:

private void invokeUserEventTriggered(Object event) {if (invokeHandler()) {try {((ChannelInboundHandler) handler()).userEventTriggered(this, event);} catch (Throwable t) {invokeExceptionCaught(t);}} else {fireUserEventTriggered(event);}} private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {if (invokeHandler()) {try {((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);} catch (Throwable t) {notifyOutboundHandlerException(t, promise);}} else {bind(localAddress, promise);}}

所以,從AbstractChannelHandlerContext可以得知,ChannelHandlerContext接口中定義的方法都是調(diào)用的handler中具體的實現(xiàn),Context只是對handler的封裝。

DefaultChannelHandlerContext

DefaultChannelHandlerContext是AbstractChannelHandlerContext的一個具體實現(xiàn)。

我們在講解AbstractChannelHandlerContext的時候提到過,AbstractChannelHandlerContext中并沒有定義具體的handler的實現(xiàn),而這個實現(xiàn)是在DefaultChannelHandlerContext中進行的。

DefaultChannelHandlerContext很簡單,我們看一下它的具體實現(xiàn):

final class DefaultChannelHandlerContext extends AbstractChannelHandlerContext {private final ChannelHandler handler;DefaultChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {super(pipeline, executor, name, handler.getClass());this.handler = handler;}@Overridepublic ChannelHandler handler() {return handler;} }

DefaultChannelHandlerContext中額外提供了一個ChannelHandler屬性,用來存儲傳入的ChannelHandler。

到此DefaultChannelHandlerContext可以傳入ChannelHandlerContext中一切必須的handler,channel,pipeline和EventExecutor。

總結(jié)

本節(jié)我們介紹了ChannelHandlerContext和它的幾個基本實現(xiàn),了解到了ChannelHandlerContext是對handler,channel和pipline的封裝,ChannelHandlerContext中的業(yè)務(wù)邏輯,實際上是調(diào)用的是底層的handler的對應方法。這也是我們在自定義handler中需要實現(xiàn)的方法。

本文已收錄于 http://www.flydean.com/04-4-netty-channelhandlercontext/

最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發(fā)現(xiàn)!

歡迎關(guān)注我的公眾號:「程序那些事」,懂技術(shù),更懂你!

總結(jié)

以上是生活随笔為你收集整理的netty系列之:channelHandlerContext详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。