Можем ли мы обрабатывать исключения, такие как конструкция 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 //с демо-тестом
@JAsgarov, очевидно, мой вопрос в том, как избежать такого поведения? Если вообще возможно.
Одним (несколько некрасивым) решением было бы сохранить, было ли обработано исключение, и проверить перед применением pointcut. Лучшим решением было бы создавать определенные исключения, а не суперкласс другого исключения, которое вы создаете.
@JAsgarov, спасибо за твои мысли по этой теме. Надеюсь, что также будут предложены нестандартные решения.
SO — это не ваша личная служба написания кода — решение должно исходить от вас. Мы здесь только для того, чтобы исправлять ошибки и направлять вас в правильном направлении. Пожалуйста.
Во-первых, говорите только за себя; не как ИТ-влиятель. И в моем вопросе нет ошибок: возможно, кто-то уже решал подобную проблему. P.S. «готовое решение» не предполагает code writing ;)




Аспект ведет себя точно так, как ожидалось, так, как вы его задумали. Старайтесь не сравнивать яблоки с грушами. В совете @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 и т. д. и добиться того же поведения с помощью сигнатур методов. Из коробки Кажется, это невозможно... Подожду еще немного и – за неимением других ответов – приму ваш👌
В настоящее время я являюсь сопровождающим AspectJ. Вы можете мне поверить, что ваше представление о том, как вы представляете себе работу AspectJ, — всего лишь фантазия. То, что вы желаете, чтобы оно работало по-другому, еще не означает, что оно сбывается. Я показал вам два способа обработки исключений, оба на 100% соответствуют семантике Java. Если вам нужно что-то еще, смело разрабатывайте свой собственный инструмент АОП.
У меня больше нет вопросов) ти, сэр🤝
это вполне естественно, учитывая, что
RuntimeExceptionявляется подклассом классаException. Таким образом, в случаеRuntimeExceptionбудут применяться обе точки.