ChannelInitializer 的添加
前面我們已經(jīng)分析過Channel 的組成,其中我們了解到,最開始的時(shí)候ChannelPipeline 中含有兩個(gè)ChannelHandlerContext(同時(shí)也是ChannelHandler),但是這個(gè)Pipeline 并不能實(shí)現(xiàn)什么特殊的功能,因?yàn)槲覀冞€沒有給它添加自定義的ChannelHandler。通常來說,我們在初始化Bootstrap,會(huì)添加我們自定義的ChannelHandler,就以我們具體的客戶端啟動(dòng)代碼片段來舉例:
Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) .option(ChannelOption.SO_KEEPALIVE, true) .handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new ChatClientHandler(nickName));} });上面代碼的初始化過程,相信大家都不陌生。在調(diào)用handler 時(shí),傳入了ChannelInitializer 對象,它提供了一個(gè)initChannel()方法給我我們初始化ChannelHandler。那么這個(gè)初始化過程是怎樣的呢?下面我們來揭開它的神秘面紗。ChannelInitializer 實(shí)現(xiàn)了ChannelHandler,那么它是在什么時(shí)候添加到ChannelPipeline 中的呢?通過代碼跟蹤,我們發(fā)現(xiàn)它是在Bootstrap 的init()方法中添加到ChannelPipeline 中的,其代碼如下:
void init(Channel channel) throws Exception {ChannelPipeline p = channel.pipeline();p.addLast(config.handler());//略去N 句代碼 }從上面的代碼可見,將handler()返回的ChannelHandler 添加到Pipeline 中,而handler()返回的其實(shí)就是我們在初始化Bootstrap 時(shí)通過handler()方法設(shè)置的ChannelInitializer 實(shí)例,因此這里就是將ChannelInitializer 插入到了Pipeline的末端。此時(shí)Pipeline 的結(jié)構(gòu)如下圖所示:
這時(shí)候,有小伙伴可能就有疑惑了,我明明插入的是一個(gè)ChannelInitializer 實(shí)例,為什么在ChannelPipeline 中的雙向鏈表中的元素卻是一個(gè)ChannelHandlerContext 呢?我們繼續(xù)去源碼中尋找答案。
剛才,我們提到,在Bootstrap 的init()方法中會(huì)調(diào)用p.addLast()方法,將ChannelInitializer 插入到鏈表的末端:
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) { final AbstractChannelHandlerContext newCtx; synchronized (this) {checkMultiplicity(handler);newCtx = newContext(group, filterName(name, handler), handler);addLast0(newCtx);// 略去N 句代碼return this; } private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler); }addLast()有很多重載的方法,我們只需關(guān)注這個(gè)比較重要的方法就行。上面的addLast()方法中,首先檢查ChannelHandler 的名字是否是重復(fù),如果不重復(fù),則調(diào)用newContex()方法為這個(gè)Handler 創(chuàng)建一個(gè)對應(yīng)的DefaultChannelHandlerContext 實(shí)例,并與之關(guān)聯(lián)起來(Context 中有一個(gè)handler 屬性保存著對應(yīng)的Handler 實(shí)例)。為了添加一個(gè)handler 到pipeline 中,必須把此handler 包裝成ChannelHandlerContext。因此在上面的代碼中我們可以看到新實(shí)例化了一個(gè)newCtx 對象,并將handler 作為參數(shù)傳遞到構(gòu)造方法中。那么我們來看一下實(shí)例化的
DefaultChannelHandlerContext 到底有什么玄機(jī)吧。首先看它的構(gòu)造器:
在DefaultChannelHandlerContext 的構(gòu)造器中,調(diào)用了兩個(gè)很有意思的方法:isInbound()與isOutbound(),這兩個(gè)方法是做什么的呢?
private static boolean isInbound(ChannelHandler handler) {return handler instanceof ChannelInboundHandler; } private static boolean isOutbound(ChannelHandler handler) {return handler instanceof ChannelOutboundHandler; }從源碼中可以看到,當(dāng)一個(gè)handler 實(shí)現(xiàn)了ChannelInboundHandler 接口,則isInbound 返回true;類似地,當(dāng)一個(gè)handler 實(shí)現(xiàn)了ChannelOutboundHandler 接口,則isOutbound 就返回true。而這兩個(gè)boolean 變量會(huì)傳遞到父類AbstractChannelHandlerContext 中,并初始化父類的兩個(gè)字段:inbound 與outbound。
那么這里的ChannelInitializer 所對應(yīng)的DefaultChannelHandlerContext 的inbound 與inbound 字段分別是什么呢? 那就看一下ChannelInitializer 到底實(shí)現(xiàn)了哪個(gè)接口不就行了?如下是ChannelInitializer 的類層次結(jié)構(gòu)圖:
從類圖中可以清楚地看到,ChannelInitializer 僅僅實(shí)現(xiàn)了ChannelInboundHandler 接口,因此這里實(shí)例化的DefaultChannelHandlerContext 的inbound = true,outbound = false。
兜了一圈,不就是inbound 和outbound 兩個(gè)字段嘛,為什么需要這么大費(fèi)周折地分析一番?其實(shí)這兩個(gè)字段關(guān)系到pipeline 的事件的流向與分類,因此是十分關(guān)鍵的,不過我在這里先賣個(gè)關(guān)子, 后面我們再來詳細(xì)分析這兩個(gè)字段所起的作用。至此, 我們暫時(shí)先記住一個(gè)結(jié)論:ChannelInitializer 所對應(yīng)的DefaultChannelHandlerContext 的inbound = true,outbound = false。
當(dāng)創(chuàng)建好Context 之后,就將這個(gè)Context 插入到Pipeline 的雙向鏈表中,基礎(chǔ)較差的可以將下面的邏輯用圖畫出來:
private void addLast0(AbstractChannelHandlerContext newCtx) {AbstractChannelHandlerContext prev = tail.prev;newCtx.prev = prev;newCtx.next = tail;prev.next = newCtx;tail.prev = newCtx; }?
總結(jié)
以上是生活随笔為你收集整理的ChannelInitializer 的添加的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 再探ChannelPipeline 的初
- 下一篇: 自定义ChannelHandler 的添