netty应该怎样处理异常

netty应该怎样处理异常

netty 在ChannelInBouindHandler中为我们提供了exceptionCaught()方法,看下源码来看看他在什么情况下会被调用

首先点开 ctx.fireChannelRead(msg);的源码查看,发现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Override
public ChannelHandlerContext fireChannelRead(final Object msg) {
invokeChannelRead(findContextInbound(MASK_CHANNEL_READ), msg);
return this;
}

static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelRead(m);
} else {
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeChannelRead(m);
}
});
}
}

private void invokeChannelRead(Object msg) {
if (invokeHandler()) {
try {
((ChannelInboundHandler) handler()).channelRead(this, msg);
} catch (Throwable t) {
notifyHandlerException(t);
}
} else {
fireChannelRead(msg);
}
}


上面代码会在pinline中查找下一个inHandler,并回掉他的ChannelRead方法,且用try catch处理回掉过程。
如果报错会调用notifyHandlerException(t)方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private void notifyHandlerException(Throwable cause) {
if (inExceptionCaught(cause)) {
if (logger.isWarnEnabled()) {
logger.warn(
"An exception was thrown by a user handler " +
"while handling an exceptionCaught event", cause);
}
return;
}

invokeExceptionCaught(cause);
}

private void invokeExceptionCaught(final Throwable cause) {
if (invokeHandler()) {
try {
handler().exceptionCaught(this, cause);
} catch (Throwable error) {
if (logger.isDebugEnabled()) {
logger.debug(
"An exception {}" +
"was thrown by a user handler's exceptionCaught() " +
"method while handling the following exception:",
ThrowableUtil.stackTraceToString(error), cause);
} else if (logger.isWarnEnabled()) {
logger.warn(
"An exception '{}' [enable DEBUG level for full stacktrace] " +
"was thrown by a user handler's exceptionCaught() " +
"method while handling the following exception:", error, cause);
}
}
} else {
fireExceptionCaught(cause);
}
}

notifyHandlerException(t)方法会调用handler()即当前handler的exceptionCaught(this, cause);方法

如果当前handler实现ChannelInboundHandlerAdapter且没实现exceptionCaught方法的话,默认会调用 ctx.fireExceptionCaught(cause),即下一个handler的exceptionCaught方法。

总结

​ netty中执行handler报错时,会先调用当前handler的exceptionCaught方法,如果没有当前没重写exceptionCaught方法会调用下一个handler的exceptionCaught方法。
​ 所以如果错误需要在当前handler处理,则重写exceptionCaught方法,自己选择要不要将异常传递下去,
如果当前handler不能处理,可以在pipline链最后一位放置一个重写exceptionCaught方法的handler
,放在pipline最后一位即可。

​ 有一种情况下,ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE,这是一个监听器,它会将错误从head节点向下传播。


netty应该怎样处理异常
https://www.huangchaoyu.com/1825389021.html
作者
hcy
发布于
2019年11月8日
更新于
2024年8月17日
许可协议