«1. Обзор

В этой быстрой статье мы рассмотрим обработку исключений в Netty.

Проще говоря, Netty — это платформа для создания высокопроизводительных асинхронных и управляемых событиями сетевых приложений. Операции ввода-вывода обрабатываются внутри его жизненного цикла с использованием методов обратного вызова.

Более подробную информацию о фреймворке и о том, как начать работу с ним, можно найти в нашей предыдущей статье здесь.

2. Обработка исключений в Netty

Как упоминалось ранее, Netty является системой, управляемой событиями, и имеет методы обратного вызова для определенных событий. Исключениями являются и такие события.

Исключения могут возникать при обработке данных, полученных от клиента, или во время операций ввода-вывода. Когда это происходит, запускается специальное событие исключения.

2.1. Обработка исключений в канале происхождения

Событие, перехваченное исключением, при запуске обрабатывается методом exceptionsCaught() объекта ChannelInboundHandler или его адаптеров и подклассов.

Обратите внимание, что обратный вызов устарел в интерфейсе ChannelHandler. Теперь он ограничен интерфейсом ChannelInboudHandler.

Метод принимает в качестве параметров объект Throwable и объект ChannelHandlerContext. Объект Throwable можно использовать для печати трассировки стека или получения локализованного сообщения об ошибке.

Итак, давайте создадим обработчик канала ChannelHandlerA и переопределим его exceptionCaught() с помощью нашей реализации:

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) 
  throws Exception {
 
    logger.info(cause.getLocalizedMessage());
    //do more exception handling
    ctx.close();
}

В приведенном выше фрагменте кода мы записали сообщение об исключении, а также вызвали close() ChannelHandlerContext.

Это закроет канал между сервером и клиентом. По сути, заставляя клиента отключиться и завершить работу.

2.2. Распространение исключений

В предыдущем разделе мы обработали исключение в его исходном канале. Однако на самом деле мы можем передать исключение другому обработчику канала в конвейере.

Вместо регистрации сообщения об ошибке и вызова ctx.close() мы будем использовать объект ChannelHandlerContext для ручного запуска другого события, перехваченного исключением.

Это приведет к вызову exceptionCaught() следующего обработчика канала в конвейере.

Давайте изменим фрагмент кода в ChannelHandlerA, чтобы событие распространялось вызовом ctx.fireExceptionCaught():

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) 
  throws Exception {
 
    logger.info("Exception Occurred in ChannelHandler A");
    ctx.fireExceptionCaught(cause);
}

Кроме того, давайте создадим еще один обработчик канала, ChannelHandlerB, и переопределим его exceptionCaught() с помощью этой реализации: ~~ ~

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) 
  throws Exception {
 
    logger.info("Exception Handled in ChannelHandler B");
    logger.info(cause.getLocalizedMessage());
    //do more exception handling
    ctx.close();
}

В классе Server каналы добавляются в конвейер в следующем порядке:

ch.pipeline().addLast(new ChannelHandlerA(), new ChannelHandlerB());

Распространение событий, перехваченных исключениями, вручную полезно в тех случаях, когда все исключения обрабатываются одним назначенным обработчиком канала.

3. Заключение

В этом руководстве мы рассмотрели, как обрабатывать исключения в Netty с помощью метода обратного вызова и как при необходимости распространять исключения.

Полный исходный код доступен на Github.