自定义ChannelHandler 的添加过程
前面我們已經(jīng)分析了ChannelInitializer 是如何插入到Pipeline 中的,接下來(lái)就來(lái)探討ChannelInitializer 在哪里被調(diào)用,ChannelInitializer 的作用以及我們自定義的ChannelHandler 是如何插入到Pipeline 中的。
先簡(jiǎn)單復(fù)習(xí)一下Channel 的注冊(cè)過(guò)程:
1、首先在AbstractBootstrap 的initAndRegister()中,通過(guò)group().register(channel),調(diào)用MultithreadEventLoopGroup 的register()方法。
2、在MultithreadEventLoopGroup 的register()中調(diào)用next()獲取一個(gè)可用的SingleThreadEventLoop,然后調(diào)用它的register()方法。
3、在SingleThreadEventLoop 的register()方法中,通過(guò)channel.unsafe().register(this, promise)方法獲取channel的unsafe()底層IO 操作對(duì)象,然后調(diào)用它的register()。
4、在AbstractUnsafe 的register()方法中,調(diào)用register0()方法注冊(cè)Channel 對(duì)象。
5、在AbstractUnsafe 的register0()方法中,調(diào)用AbstractNioChannel 的doRegister()方法。
6、AbstractNioChannel 的doRegister()方法調(diào)用javaChannel().register(eventLoop().selector, 0, this)將Channel對(duì)應(yīng)的Java NIO 的SockerChannel 對(duì)象注冊(cè)到一個(gè)eventLoop 的Selector 中,并且將當(dāng)前Channel 作為attachment。
而我們自定義ChannelHandler 的添加過(guò)程,發(fā)生在AbstractUnsafe 的register0()方法中,在這個(gè)方法中調(diào)用了pipeline.fireChannelRegistered()方法,其代碼實(shí)現(xiàn)如下:
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();}});} }很顯然,這個(gè)代碼會(huì)從head 開(kāi)始遍歷Pipeline 的雙向鏈表,然后找到第一個(gè)屬性inbound 為true 的ChannelHandlerContext 實(shí)例。想起來(lái)了沒(méi)?我們?cè)谇懊娣治鯟hannelInitializer 時(shí),花了大量的篇幅來(lái)分析了inbound和outbound 屬性,現(xiàn)在這里就用上了。回想一下,ChannelInitializer 實(shí)現(xiàn)了ChannelInboudHandler,因此它所對(duì)應(yīng)的ChannelHandlerContext 的inbound 屬性就是true,因此這里返回就是ChannelInitializer 實(shí)例所對(duì)應(yīng)的ChannelHandlerContext 對(duì)象,如下圖所示:
當(dāng)獲取到inbound 的Context 后,就調(diào)用它的invokeChannelRegistered()方法:
private void invokeChannelRegistered() {if (invokeHandler()) {try {((ChannelInboundHandler) handler()).channelRegistered(this);} catch (Throwable t) {notifyHandlerException(t);}} else {fireChannelRegistered();} }我們已經(jīng)知道,每個(gè)ChannelHandler 都和一個(gè)ChannelHandlerContext 關(guān)聯(lián),我們可以通過(guò)ChannelHandlerContext獲取到對(duì)應(yīng)的ChannelHandler。因此很明顯,這里handler()返回的對(duì)象其實(shí)就是一開(kāi)始我們實(shí)例化的ChannelInitializer 對(duì)象,并接著調(diào)用了ChannelInitializer 的channelRegistered()方法。看到這里, 應(yīng)該會(huì)覺(jué)得有點(diǎn)眼熟了。ChannelInitializer 的channelRegistered()這個(gè)方法我們?cè)谝婚_(kāi)始的時(shí)候已經(jīng)接觸到了,但是我們并沒(méi)有深入地分析這個(gè)方法的調(diào)用過(guò)程。下面我們來(lái)看這個(gè)方法中到底有什么玄機(jī),繼續(xù)看代碼:
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())這個(gè)方法我們也很熟悉,它就是我們?cè)诔跏蓟疊ootstrap 時(shí),調(diào)用handler 方法傳入的匿名內(nèi)部類(lèi)所實(shí)現(xiàn)的方法:
.handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new ChatClientHandler(nickName));} });因此,當(dāng)調(diào)用這個(gè)方法之后, 我們自定義的ChannelHandler 就插入到了Pipeline,此時(shí)Pipeline 的狀態(tài)如下圖所示:
當(dāng)添加完成自定義的ChannelHandler 后,在finally 代碼塊會(huì)刪除自定義的ChannelInitializer,也就是remove(ctx)最終調(diào)用ctx.pipeline().remove(this),因此最后的Pipeline 的狀態(tài)如下:
至此,自定義ChannelHandler 的添加過(guò)程也分析得差不多了。
?
總結(jié)
以上是生活随笔為你收集整理的自定义ChannelHandler 的添加过程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ChannelInitializer 的
- 下一篇: EventLoopGroup 与Reac