在之前的文章中解读了Netty对于一条连接的各个状态的生命周期进行了解读
1、ChannelInitializer的实现原理
- 在定义handler的时候通过
childHandler()
方法设置了一个handle/也就是ChannelInitializer
- 在
ChannelInitializer
的initChannel()
方法中,通过获取channel对应的管道,在里面加入各种方法
//xxxxxxxxxxxxxx省略代码```
.childHandler(new ChannelInitializer<NioSocketChannel>() {
protected void initChannel(NioSocketChannel ch) {
ch.pipeline().addLast(new LifeCyCleTestHandler());
ch.pipeline().addLast(new PacketDecoder());
ch.pipeline().addLast(new LoginRequestHandler());
ch.pipeline().addLast(new MessageRequestHandler());
ch.pipeline().addLast(new PacketEncoder());
}
});
ChannelInitializer
其实就利用了Netty的处理程序生命周期中channelRegistered()
与handlerAdded()
两个特性
2、ChannelInitializer
类源代码
protected abstract void initChannel(C ch) throws Exception;
public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
// ...
initChannel(ctx);
// ...
}
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
// ...
if (ctx.channel().isRegistered()) {
initChannel(ctx);
}
// ...
}
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
if (initMap.putIfAbsent(ctx, Boolean.TRUE) == null) {
initChannel((C) ctx.channel());
// ...
return true;
}
return false;
}
1、ChannelInitializer
定义了一个抽象的方法initChannel()
,这个抽象方法由我们自行实现,我们在服务端启动的流程里面的实现逻辑就是往pipeline里面塞我们的handler链
2、handlerAdded()
和channelRegistered()
方法,都会尝试去调用initChannel()
方法,initChannel()
使用putIfAbsent()
来防止initChannel()
被调用多次。在handlerAdded()
方法被调用的时候,通道其实已经和某个线程绑定上了;
3、handlerAdded()
与handlerRemoved()
:通常可以用在一些资源的申请和释放
4、channelActive()
与channelInActive()
:TCP连接的建立与释放
5、channelRead()
:解包粘包原理,服务端根据自定义协议来进行拆包,其实就是在这个方法里面,每次读到一定的数据,都会累加到一个容器里面,然后判断是否能够拆出来一个完整的数据包,如果够的话就拆了之后,往下进行传递。
6、channelReadComplete()
:我们在每次向客户端写数据的时候,都通过writeAndFlush()
的方法写并刷新到前面,其实这种方式不是特别高效,我们可以在之前调用writeAndFlush()
的地方都调用write()
方法,然后在这个方面里面调用ctx.channel().flush()
方法,相当于一个批量刷新的机制,当然,如果你对性能要求没那么高,writeAndFlush()
就可以。