本文主要記錄下本人看Netty源碼中關(guān)于ChannelPipeline的細(xì)節(jié)問題,為原創(chuàng)內(nèi)容,如有文中有書寫或其他問題,請(qǐng)留言指導(dǎo)修正,互相交流,共同進(jìn)步,本人QQ:417213902。
認(rèn)識(shí)ChannelPipeline

ChannelPipeline內(nèi)部是實(shí)現(xiàn)類似責(zé)任鏈的調(diào)用,每一個(gè)handler記錄下一個(gè)handler,感覺有點(diǎn)像servlet中的Filter鏈。
源碼解讀

首先,看下ChannelPipeline接口主要繼承ChannelInboundInvoker 和ChannelOutboundInvoker這兩個(gè)接口
- ChannelInboundInvoker :AbstractChannelHandlerContext中實(shí)現(xiàn)了該接口,并調(diào)用ChannelInboundHandler的接口,從而實(shí)現(xiàn)真正的調(diào)用
- ChannelOutboundInvoker :AbstractChannelHandlerContext中實(shí)現(xiàn)了該接口,并調(diào)用ChannelOutboundHandler的接口,從而實(shí)現(xiàn)真正的調(diào)用
- ChannelInboundHandler:對(duì)從客戶端發(fā)往服務(wù)端的報(bào)文進(jìn)行處理,一般用來執(zhí)行解碼、讀取客戶端數(shù)據(jù)、進(jìn)行業(yè)務(wù)處理等,按照注冊(cè)的先后順序執(zhí)行,若要自行實(shí)現(xiàn)ChannelInboundHandler接口,直接繼承ChannelInboundHandlerAdapter,因?yàn)榇祟愐呀?jīng)有默認(rèn)接口實(shí)現(xiàn)。
- ChannelOutboundHandler:對(duì)從服務(wù)端發(fā)往客戶端的報(bào)文進(jìn)行處理,一般用來進(jìn)行編碼、發(fā)送報(bào)文到客戶端,按照注冊(cè)的先后順序逆序執(zhí)行 ,同上。
其次,來講下ChannelPipeline的初始化,以下代碼是Netty-4.1官方提供的Example 中服務(wù)端代碼(io.netty.example.echo.EchoServer),這里做了不少的事情,這里除了ChannelPipeline初始化,其他內(nèi)容會(huì)在其他的文章中做闡述,這里我們主要看 .channel(NioServerSocketChannel.class)
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
//p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new EchoServerHandler());
}
});
ChannelFuture f = b.bind(PORT).sync();
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}

這是NioServerSocketChannel的類結(jié)構(gòu)層次圖,這里我們主要看AbstractChannel這個(gè)抽象類,查看其構(gòu)造方法,這里同時(shí)也實(shí)例化了一個(gè)DefaultChannelPipeline。

它其實(shí)是Netty中ChannelPipeline接口的具體實(shí)現(xiàn)類,是ChannelPipeline的核心類,責(zé)任鏈的一系列實(shí)現(xiàn)基本都是通過這個(gè)類來操作。

我們?cè)賮砜聪翫efaultChannelPipeline的構(gòu)造方法中實(shí)例化了兩個(gè)類,分別是TailContext和HeadContext,都繼承或?qū)崿F(xiàn)了這兩個(gè)接口ChannelHandlerContext 和 ChannelHandler ,它們互相指向, 構(gòu)成一個(gè)類似于雙向鏈表的容器
-
TailContext :我的理解是它是整個(gè)鏈的最后,雖然它實(shí)現(xiàn)了ChannelInboundHandler,但是實(shí)現(xiàn)的方法都是空實(shí)現(xiàn),我認(rèn)為它針對(duì)Inbound沒有實(shí)際上的作用(有點(diǎn)怪異),查資料網(wǎng)上有說法,因?yàn)樵谧詈?,沒有具體實(shí)現(xiàn),說明是一種優(yōu)雅的退出。
image.png -
HeadContext :我的理解是它是整個(gè)鏈的第一個(gè),它對(duì)ChannelInboundHandler和ChannelOutboundHandler所有方法都有了實(shí)現(xiàn)
image.png ChannelHandlerContext :是ChannelPipeline 鏈中每一個(gè)handler 的上下文信息,負(fù)責(zé)調(diào)用對(duì)應(yīng)的ChannelHandler,并指定下一個(gè)ChannelHandlerContext(我的理解)
ChannelHandler : 負(fù)責(zé)執(zhí)行對(duì)應(yīng)的handler,并回調(diào)context進(jìn)行下一次調(diào)用

最后ChannelPipeline真正在哪加載的?
我們會(huì)看到上面摘取的部分Example源碼中,有初始化ChannelPipeline,本以為此處就是加載處,但是后面看到ServerBootstrap.bind方法后,發(fā)現(xiàn)里面有個(gè)init方法,這里又再次重新加載了,我猜想是因?yàn)閯傞_始的Channel通道沒有被綁定或注冊(cè)到真正的Channel上,還需要進(jìn)一步探討。

2017-12-17 01:24

