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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

自定义ChannelHandler 的添加过程

發布時間:2024/4/13 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自定义ChannelHandler 的添加过程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面我們已經分析了ChannelInitializer 是如何插入到Pipeline 中的,接下來就來探討ChannelInitializer 在哪里被調用,ChannelInitializer 的作用以及我們自定義的ChannelHandler 是如何插入到Pipeline 中的。

先簡單復習一下Channel 的注冊過程:

1、首先在AbstractBootstrap 的initAndRegister()中,通過group().register(channel),調用MultithreadEventLoopGroup 的register()方法。

2、在MultithreadEventLoopGroup 的register()中調用next()獲取一個可用的SingleThreadEventLoop,然后調用它的register()方法。

3、在SingleThreadEventLoop 的register()方法中,通過channel.unsafe().register(this, promise)方法獲取channel的unsafe()底層IO 操作對象,然后調用它的register()。

4、在AbstractUnsafe 的register()方法中,調用register0()方法注冊Channel 對象。

5、在AbstractUnsafe 的register0()方法中,調用AbstractNioChannel 的doRegister()方法。

6、AbstractNioChannel 的doRegister()方法調用javaChannel().register(eventLoop().selector, 0, this)將Channel對應的Java NIO 的SockerChannel 對象注冊到一個eventLoop 的Selector 中,并且將當前Channel 作為attachment。

而我們自定義ChannelHandler 的添加過程,發生在AbstractUnsafe 的register0()方法中,在這個方法中調用了pipeline.fireChannelRegistered()方法,其代碼實現如下:

public final ChannelPipeline fireChannelRegistered() {AbstractChannelHandlerContext.invokeChannelRegistered(head);return this; }

再看AbstractChannelHandlerContext 的invokeChannelRegistered()方法:

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();}});} }

很顯然,這個代碼會從head 開始遍歷Pipeline 的雙向鏈表,然后找到第一個屬性inbound 為true 的ChannelHandlerContext 實例。想起來了沒?我們在前面分析ChannelInitializer 時,花了大量的篇幅來分析了inbound和outbound 屬性,現在這里就用上了。回想一下,ChannelInitializer 實現了ChannelInboudHandler,因此它所對應的ChannelHandlerContext 的inbound 屬性就是true,因此這里返回就是ChannelInitializer 實例所對應的ChannelHandlerContext 對象,如下圖所示:

當獲取到inbound 的Context 后,就調用它的invokeChannelRegistered()方法:

private void invokeChannelRegistered() {if (invokeHandler()) {try {((ChannelInboundHandler) handler()).channelRegistered(this);} catch (Throwable t) {notifyHandlerException(t);}} else {fireChannelRegistered();} }

我們已經知道,每個ChannelHandler 都和一個ChannelHandlerContext 關聯,我們可以通過ChannelHandlerContext獲取到對應的ChannelHandler。因此很明顯,這里handler()返回的對象其實就是一開始我們實例化的ChannelInitializer 對象,并接著調用了ChannelInitializer 的channelRegistered()方法。看到這里, 應該會覺得有點眼熟了。ChannelInitializer 的channelRegistered()這個方法我們在一開始的時候已經接觸到了,但是我們并沒有深入地分析這個方法的調用過程。下面我們來看這個方法中到底有什么玄機,繼續看代碼:

public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {if (initChannel(ctx)) {ctx.pipeline().fireChannelRegistered();} else {ctx.fireChannelRegistered();} } private boolean initChannel(ChannelHandlerContext ctx) throws Exception {if (initMap.putIfAbsent(ctx, Boolean.TRUE) == null) { // Guard againsttry {initChannel((C) ctx.channel());} catch (Throwable cause) {exceptionCaught(ctx, cause);} finally {remove(ctx);}return true;}return false; }

initChannel((C) ctx.channel())這個方法我們也很熟悉,它就是我們在初始化Bootstrap 時,調用handler 方法傳入的匿名內部類所實現的方法:

.handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new ChatClientHandler(nickName));} });

因此,當調用這個方法之后, 我們自定義的ChannelHandler 就插入到了Pipeline,此時Pipeline 的狀態如下圖所示:

當添加完成自定義的ChannelHandler 后,在finally 代碼塊會刪除自定義的ChannelInitializer,也就是remove(ctx)最終調用ctx.pipeline().remove(this),因此最后的Pipeline 的狀態如下:

至此,自定義ChannelHandler 的添加過程也分析得差不多了。

?

總結

以上是生活随笔為你收集整理的自定义ChannelHandler 的添加过程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。