自定义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 的添加过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ChannelInitializer 的
- 下一篇: EventLoopGroup 与Reac