Рубрики
Без рубрики

Обработка исключений в различных типах приложений

Введение Обработка исключений является общей для большинства языков программирования и механизмов… С тегами java, csharp, web dev, архитектура.

Обработка исключений является общей для большинства языков программирования, а механизмы и поведение аналогичны в большинстве языков: try\catch\finally. Это хорошо задокументировано. Мы не собираемся это обсуждать.

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

Давайте начнем с некоторых основных принципов.

Исключение – это событие во время выполнения программы, которое нарушает нормальный поток и не позволяет программе выполнять то, что от нее ожидается, например, программа пытается выполнить запись в файл журнала, но файл не может быть открыт.

В таких условиях ошибки среда выполнения ищет обработчики (try-catch), которые зарегистрированы для обработки таких исключений, и когда обработчик найден, он вызывается с объектом исключения, содержащим информацию о событии. На следующей диаграмме показан обычный поток программы (Среда выполнения > main > Method1 > Method2) и поток, когда в Method2 возникает исключение.

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

Два прохода против Одного прохода

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

JVM, с другой стороны, запускает finally block в методе, если обработчик не найден в этом методе, а затем перемещается вверх по стеку вызовов.

Подробное объяснение см. в разделах Обработка исключений CLR и Обработка исключений JVM .

Асинхронное выполнение

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

Ниже приведен Java-код, который запускает метод в новом потоке и завершает работу.

public class AsyncRun implements Runnable {
  @Override
  public void run() {
        // TODO Auto-generated method stub
    System.out.println("AsyncRun.run on thread " + Thread.currentThread().getId());
    throw new ArithmeticException();
  }    
}

public static void main( String[] args ) {
  try {
    Thread t = new Thread(new AsyncRun());
    t.start();
    System.out.println( "main on thread " + Thread.currentThread().getId());
    throw new NullPointerException();
  }
  catch(Exception ex)
  {
    System.out.println(ex.getClass().getName() + " handled");
  }
}

Это было бы результатом:

main on thread 1
AsyncRun.run on thread 15
java.lang.NullPointerException handled
Exception in thread "Thread-0" java.lang.ArithmeticException
        at exceptionhandling.AsyncRun.run(AsyncRun.java:13)
        at java.base/java.lang.Thread.run(Thread.java:835)

Исключение NullPointerException , вызванное методом main , обрабатывается методом try-catch в main , но исключение в методе Async Run.run обрабатывается как необработанное исключение, поскольку JVM не удалось найти обработчик в стеке вызовов в потоке, выполняющем ASYNCRUN.run . Async Run.run – это первый метод, который вызывается в потоке, поэтому стек вызовов заканчивается на этом, try-catch в методе main не будет применяться к AsyncRun.run .

Однако, в отличие от основного потока, необработанное исключение в отдельном потоке не привело к сбою.Net имеет такое же поведение, как и Java, для асинхронного выполнения.

Альтернатива исключениям

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

Обработка исключений требуется в первую очередь по следующим причинам:

  1. Предотвращение сбоев : Необработанное исключение может привести к сбою приложения. Таким образом, даже для предотвращения сбоя приложению необходимо обрабатывать исключения.
  2. Альтернативный поток : В некоторых случаях может возникнуть необходимость изменить поток работы программы в случае ошибки, например, на портале онлайн-покупок, когда запрос платежного API выдает исключение, путешествие пользователя потребует, чтобы приложение обработало его и вернуло пользователя на страницу корзины, чтобы пользователь мог снова инициировать платеж.
  3. Ведение журнала : Это необходимо для устранения неполадок.

Где для обработки исключений очень важно, и в целом существует два типа мест, где следует обрабатывать исключения:

  1. Все Точки входа в программу \приложение для предотвращения сбоев. Как мы видели выше, когда исключение достигает среды выполнения или фреймворка, это может привести к сбою. Точки входа могут быть одной или несколькими, например:

    1. основной способ
    2. Обработчики событий в приложении пользовательского интерфейса – SPA или настольном приложении
    3. Открытые методы на контроллере в MVC
    4. Метод запуска фонового потока
  2. Для поддержки различных потоков в случае ошибки требуется обработка исключений там, где необходимо реализовать такие перенаправления.

Теперь давайте попробуем посмотреть, как все это применимо к различным типам приложений:

Библиотека

  • Библиотека – это набор функций/классов, ориентированных на некоторую проблемную область.
  • Библиотеки не управляют потоком программы. Функции библиотек вызываются основной программой с некоторым вводом, и они возвращают некоторый вывод или обеспечивают некоторое поведение, например, RecommendationEngine исполняемый файл использует библиотеки для ведения журнала, доступа к данным и т.д. Для выполнения своей работы, но поток программы управляется только исполняемым файлом.
  • Ответственность за предотвращение сбоя или реализацию альтернативного потока лежит на основной программе.
  • Следовательно, код в библиотеке не должен подавлять исключения , поскольку это помешало бы вызывающему приложению выполнять требования к альтернативному потоку и ведению журнала – оно может перехватывать исключения и повторно генерировать или предоставлять ожидаемый результат путем перехвата исключений.

  • Могут быть сценарии, в которых библиотеке необходимо обрабатывать исключения, как в следующем случае, но она не должна подавлять исключения. Например, продолжая приведенный выше пример, предположим, что данные могут поступать из MySQL или MongoDB, поэтому сама библиотека DataAccess полагается на другие библиотеки. Но чтобы сделать Механизм рекомендаций зависит только от Доступа к данным |/библиотеки, библиотека Доступ к данным может обрабатывать исключения из MySQL и MongoDB а затем выдает свое собственное исключение. Повторный бросок гарантировал бы, что Механизм рекомендаций получает возможность решить, что делать с исключением.

интерфейс прикладного программирования

  • API-интерфейсы можно рассматривать как библиотеку функций, доступных по сети, например, в продолжение предыдущего примера, если будет принято решение предоставить API-интерфейсы доступа к данным в качестве API-интерфейсов REST, это будет выглядеть следующим образом.
  • Как и в случае с библиотекой, вызывающий API (механизм рекомендаций) должен обрабатывать исключение, но из-за изменения характера вызова API доступа к данным исключения необходимо обрабатывать по следующим причинам:
    • API доступа к данным как библиотека : в этом случае, когда возникает исключение, вызывающий объект (механизм рекомендаций) находится в том же процессе, и среда выполнения позволяет ему обрабатывать исключение – также объект exception предоставит подробную информацию о том, что произошло, чтобы вызывающий объект мог предпринять соответствующие действия.
    • API доступа к данным как REST API : здесь вызывающий (механизм рекомендаций) не находится в том же процессе. Вызывающий ожидает действительный HTTP-ответ от REST API. Таким образом, если сам API не обрабатывает исключение, фреймворк (ASP.Net MVC, Spring MVC и т.д.) Должен обработать это и вернуть действительный HTTP-ответ, который может не предоставить вызывающей стороне достаточных сведений об ошибке.
    • Таким образом, REST API сам должен обрабатывать исключение и возвращать ответ, который вызывающий может использовать, чтобы определить, что произошла ошибка. В этом случае ответ (тело ответа API) должен будет содержать коды ошибок, и вызывающий абонент должен выполнять действия на основе кодов ошибок.

Приложение пользовательского интерфейса

  • Почти все приложения пользовательского интерфейса написаны с использованием некоторого фреймворка, при этом фреймворк вызывает приложение при возникновении какого-либо события. Это делает обработчики событий точкой входа в приложение, поэтому исключения должны перехватываться обработчиками событий.

  • Дополнительная обработка исключений в приложении пользовательского интерфейса будет варьироваться в зависимости от того, что делает приложение, например, если приложение выполняет работу в фоновых потоках, точки входа \ методы запуска потока должны обрабатывать исключения.

Рамки

  • Фреймворк – это реализация Инверсии шаблона управления. Фреймворк обнаруживает, загружает и вызывает свои плагины в событиях, которые интересуют подключаемый модуль. Как фреймворк, так и плагины взаимодействуют друг с другом, используя известные общедоступные интерфейсы, например,
  • Вот как это работает:

    • (a) Spring (framework) обнаруживает контроллеры с @Controller аннотацией к классу
    • (b) Контейнер DI будет инициализировать классы (или загружать подключаемый модуль), вызывая их конструкторы
    • (c) когда получен HTTP-запрос на соответствующий URL-адрес, Spring MVC вызывает соответствующий метод в плагине (экземпляр контроллера, созданный в (b)) и возвращает ответ.
  • На приведенной выше диаграмме вызовы из Spring в приложение – помечено символом X – являются уязвимыми точками, поскольку Spring не может предположить, что приложение не будет генерировать исключения, поэтому оно будет обрабатывать исключения например, если UserController.create метод выдает исключение, Spring MVC обработает его и запустит альтернативный поток, чтобы вернуть соответствующий HTTP-ответ, указывающий на ошибку.

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

  • Фреймворк сам по себе не может быть причиной сбоя, поэтому он должен убедиться, что он внутренне не позволяет никакому исключению оставаться необработанным и достигать среды выполнения, поскольку это может привести к сбою.

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

Оригинал: “https://dev.to/pathiknd/exception-handling-in-different-types-of-applications-38eo”