Перейти к основному содержимому

Точка присоединения против ProceedingJoinPoint в AspectJ

· 3 мин. чтения

1. Введение

В этом коротком руководстве мы узнаем о различиях между интерфейсами JoinPoint и ProceedingJoinPoint в AspectJ .

Мы расскажем об этом с кратким объяснением и примерами кода.

2. Присоединиться

JoinPoint — это интерфейс AspectJ , обеспечивающий отражающий доступ к состоянию, доступному в данной точке соединения , например к параметрам метода, возвращаемому значению или выброшенному исключению. Он также предоставляет всю статическую информацию о самом методе.

Мы можем использовать его с советами @Before , @After , @AfterThrowing и @AfterReturning . Эти pointcuts будут запускаться соответственно перед выполнением метода, после выполнения, после возврата значения или только после выдачи исключения, или только после того, как метод вернет значение.

Для лучшего понимания давайте рассмотрим базовый пример. Во-первых, нам нужно объявить pointcut. Мы определим как каждое выполнение getArticleList() из класса ArticleService :

@Pointcut("execution(* com.foreach.ArticleService.getArticleList(..))")
public void articleListPointcut(){ }

Далее мы можем определить совет. В нашем примере мы будем использовать @Before :

@Before("articleListPointcut()")
public void beforeAdvice(JoinPoint joinPoint) {
log.info(
"Method {} executed with {} arguments",
joinPoint.getStaticPart().getSignature(),
joinPoint.getArgs()
);
}

В приведенном выше примере мы используем совет @Before для регистрации выполнения метода с его параметрами. Аналогичным вариантом использования может быть регистрация исключений, возникающих в нашем коде:

@AfterThrowing(
pointcut = "articleListPointcut()",
throwing = "e"
)
public void logExceptions(JoinPoint jp, Exception e) {
log.error(e.getMessage(), e);
}

Используя совет @AfterThrowing , мы гарантируем, что ведение журнала происходит только тогда, когда возникает исключение.

3. Выполнение пункта присоединения

ProceedingJoinPoint — это расширение JoinPoint , предоставляющее дополнительный метод continue () . При вызове выполнение кода переходит к следующему совету или к целевому методу. Это дает нам возможность контролировать поток кода и решать, следует ли продолжать дальнейшие вызовы.

Это может быть просто с советом @Around , который окружает весь вызов метода:

@Around("articleListPointcut()")
public Object aroundAdvice(ProceedingJoinPoint pjp) {
Object articles = cache.get(pjp.getArgs());
if (articles == null) {
articles = pjp.proceed(pjp.getArgs());
}
return articles;
}

В приведенном выше примере мы иллюстрируем одно из самых популярных применений совета @Around . Фактический метод вызывается только в том случае, если кеш не возвращает результат. Именно так работают аннотации Spring Cache .

Мы также можем использовать советы ProceedingJoinPoint и @Around , чтобы повторить операцию в случае любого исключения:

@Around("articleListPointcut()")
public Object aroundAdvice(ProceedingJoinPoint pjp) {
try {
return pjp.proceed(pjp.getArgs());
} catch (Throwable) {
log.error(e.getMessage(), e);
log.info("Retrying operation");
return pjp.proceed(pjp.getArgs());
}
}

Это решение можно использовать, например, для повторных вызовов HTTP в случае сбоев в сети.

4. Вывод

В этой статье мы узнали о различиях между Joinpoint и ProceedingJoinPoint в AspectJ . Как всегда, весь исходный код доступен на GitHub .