文章导航

Channel的生命周期

Channel包含4个状态:

ChannelUnregistered Channel已经被创建,但还未注册到EventLoop
ChannelRegistered Channel已经被注册到EventLoop
ChannelActive Channel处于活动状态,它现在可以接受和发送数据了
ChannelInactive Channel没有连接到远程节点

ChannelHandler的生命周期

ChannelHandler接口定义了一系列生命周期操作:

类型 描述
handlerAdded 当把ChannelHandler添加到ChannelPipeline中时要调用
handlerRemoved 当从ChannelPipeline中移除ChannelHandler时被调用
exceptionCaught 当处理过程中在ChannelPipeline中有错误产生时调用

ChannelInboundHandler接口

YRSkl9.png

ChannelOutboundHandler接口

YRSew6.png

ChannelHandler适配器

YRSJmt.png

资源管理

每当调用ChannelInboundHandler.channelRead()或者ChannelOutboundHandler.write()方法来处理数据时,都需要确保没有任何的资源泄漏。Netty使用引用计数来处理池化的ByteBuf.所以在完全使用某个ByteBuf之后,调整其引用计数是很重要的。
Netty提供了class ResourceLeakDetector,它可以对应用程序缓冲区分配做大约1%的采样率进行内存泄漏检测。相关的开销是非常的小的。

级别 描述
DISABLED 禁止内存泄漏检测
SIMPLE 使用1%的默认采样率检测并报告任何发现的泄漏。(默认)
ADVANCED 使用默认的采样率,报告所发现的任何的泄漏以及对应的消息被访问的位置。
PARANOID 类是于ADVANCED,但是其间会对每次访问都进行采样。这会对性能有较大的影响。

泄漏检测级别可以通过JVM启动选项来设置:
java -Dio.netty.leakDetectionLevel=ADVANCED

ChannelPipeline接口

ChannelPipeline是一个拦截流经Channel的入站和出站事件的ChannelHandler实例链。每一个新创建的Channel都会被分配给一个新的ChannelPipeline,这项关联式永久性的,Channel既不能附加另外一个ChannelPipeline,也不能分离其当前的。
根据事件的起源事件将会被分为ChannelInboundHandler或者ChannelOutboundHandler处理。
YRNLan.png

修改ChannelPipeline

ChannelPipeline可以通过添加、删除或者替换其它的ChannelHandler来实时地修改ChannelPipeline的布局。
YRUIF1.png
ChannelPipeline还提供了访问ChannelHandler的操作:
YRdAgK.png

触发事件

ChannelPipeline的API公开了用于调用入站和出站操作的附加方法。
YRd18P.png
YRdB80.png

ChannelHandlerContext接口

ChannelHandlerContext代表了ChannelHandlerChannelPipeline之间的关联。每当有ChannelHandler添加到ChannelPipeline中时,都会创建ChannelHandlerContextChannelHandlerContext的主要功能就是管理它所关联的ChannelHandler和在同一ChannelPipeline中的其它ChannelHandler之间的交互。

异常处理

Netty提供了几种方式来处理入站和出站过程中出现的异常。

入站异常

如果需要处理入站异常,需要在对应的ChannelInboundHandler中重写exceptionCaught方法。

1
2
3
4
5
6
7
8
public class InboundExceptionHandler extends ChannelInboundHandlerAdapter{
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}

一般将异常处理的ChannelHandler放到ChannelPipeline的最后一个位置。这样在整个处理路链中无论哪个环节出了异常都可以得到处理。因为exceptionCaught()的默认实现是将异常转发给下一个HandlerHandler.

处理出站异常

处理出站异常基于以下的机制:

  • 每个出站操作都会返回一个ChannelFuture,注册到ChannelFutureChannelFutureListener将在操作完成时痛殴之该操作时注册成功还是出错了
  • 几乎所有的ChannelOutboundHandler上的方法都会传入一个ChannelPromise的实例,作为ChannelFuture的子类,ChannelPromise也可以被分配用于异步通知的监听器。但是,ChannelPromise还具有提供立即通知的可写方法。

处理方法:

1
2
3
4
5
6
7
8
9
10
ChannelFuture future = channel.write(someMessage);
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture f) {
if (!f.isSuccess()) {
f.cause().printStackTrace();
f.channel().close();
}
}
});

另一种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class OutboundExceptionHandler extends 	   ChannelOutboundHandlerAdapter {
@Override
public void write(ChannelHandlerContext ctx, Object msg,
ChannelPromise promise) {
promise.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture f) {
if (!f.isSuccess()) {
f.cause().printStackTrace();
f.channel().close();
}
}
});
}
}