Совет @AfterThrowing применяется дважды

Можем ли мы обрабатывать исключения, такие как конструкция try-catch, с помощью Spring AOP?

Когда какое-то выброшенное исключение и соответствующий аспект содержит два совета: класс исключения и его суперкласс,

@AfterThrowing(pointcut = "bean(advisedService)", throwing = "e")
void afterThrowingException(RuntimeException e) {}

@AfterThrowing(pointcut = "bean(advisedService)", throwing = "e")
void afterThrowingException(Exception e) {}

они оба подают заявку.

В простом виде catch(…){} мы можем добиться желаемого результата, упорядочивая от подкласса к суперклассу (от частного к общему):

try {
    advisedService.doSomething();
}
catch (RuntimeException e) {}
catch (Exception e) {}

и обработка ex определенного типа только один раз✔️


GitHub //с демо-тестом

это вполне естественно, учитывая, что RuntimeException является подклассом класса Exception. Таким образом, в случае RuntimeException будут применяться обе точки.

J Asgarov 01.03.2024 18:47

@JAsgarov, очевидно, мой вопрос в том, как избежать такого поведения? Если вообще возможно.

Rostik 01.03.2024 18:58

Одним (несколько некрасивым) решением было бы сохранить, было ли обработано исключение, и проверить перед применением pointcut. Лучшим решением было бы создавать определенные исключения, а не суперкласс другого исключения, которое вы создаете.

J Asgarov 01.03.2024 19:02

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

Rostik 01.03.2024 19:06

SO — это не ваша личная служба написания кода — решение должно исходить от вас. Мы здесь только для того, чтобы исправлять ошибки и направлять вас в правильном направлении. Пожалуйста.

J Asgarov 01.03.2024 19:16

Во-первых, говорите только за себя; не как ИТ-влиятель. И в моем вопросе нет ошибок: возможно, кто-то уже решал подобную проблему. P.S. «готовое решение» не предполагает code writing ;)

Rostik 01.03.2024 21:10
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
6
103
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Аспект ведет себя точно так, как ожидалось, так, как вы его задумали. Старайтесь не сравнивать яблоки с грушами. В совете @AfterThrowing вы не можете перехватывать/обрабатывать исключения, а только делать что-то поверх выбрасываемого исключения, например. регистрируйте их так, как вы это делаете. Оба ваших метода советов сработают, потому что оба среза совпадают. Пока что все нормально.

Если вам нужно другое поведение, просто измените код. Как насчет этого?

@AfterThrowing(pointcut = "bean(advisedService)", throwing = "e")
void afterThrowingException(Exception e) {
  System.out.printf(
    "AdvisedServiceAspect %s exception: %s%n",
    e instanceof RuntimeException ? "runtime" : "checked",
    e.getClass().getSimpleName()
  );
}

Или, если вы действительно хотите обрабатывать исключения, а не просто регистрировать их, воспользуйтесь советом @Around (придуманный пример):

@Around("bean(advisedService)")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
  try {
    return joinPoint.proceed();
  }
  catch (RuntimeException e) {
    System.out.println("Runtime exception caught, returning null");
    return null;
  }
  catch (Exception e) {
    throw new RuntimeException("Wrap checked exception in runtime exception", e);
  }
  // Do not handle Throwable, i.e. let it escalate
}

Мне бы просто хотелось избегать instanceOf, try-catch и т. д. и добиться того же поведения с помощью сигнатур методов. Из коробки Кажется, это невозможно... Подожду еще немного и – за неимением других ответов – приму ваш👌

Rostik 08.03.2024 10:08

В настоящее время я являюсь сопровождающим AspectJ. Вы можете мне поверить, что ваше представление о том, как вы представляете себе работу AspectJ, — всего лишь фантазия. То, что вы желаете, чтобы оно работало по-другому, еще не означает, что оно сбывается. Я показал вам два способа обработки исключений, оба на 100% соответствуют семантике Java. Если вам нужно что-то еще, смело разрабатывайте свой собственный инструмент АОП.

kriegaex 08.03.2024 13:05

У меня больше нет вопросов) ти, сэр🤝

Rostik 08.03.2024 17:45

Другие вопросы по теме