netty应该怎样处理异常

Posted by hcy on November 8, 2019

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节点向下传播。


转载请注明出处:https://www.huangchaoyu.com/2019/11/08/netty应该怎样处理异常/