Вопрос:

Spring AOP: аспект @Around не работает

java aop spring-aop

2438 просмотра

2 ответа

10 Репутация автора

Я сделал простое веб-приложение, используя Spring Boot и Spring Initializr, и попытался написать @Aspect с советами @Around .

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

Проект находится здесь: https://github.com/zalizko/spring-aop-playground

@Aspect
@Component
public final class MethodRepeater {

    @Around("execution(* *(..)) && @annotation(RetryOnFailure)")
    public Object wrap(final ProceedingJoinPoint joinPoint) throws Throwable {
        // code is here
    }
}

Итак, моя цель заключается в том, чтобы:

@RequestMapping
public String index() {
    inTry();
    return "OK";
}


@RetryOnFailure(attempts = 3, delay = 2, unit = TimeUnit.SECONDS)
public void inTry() {
    throw new RuntimeException("Exception in try " + ++counter);
}
Автор: George Zalizko Источник Размещён: 11.03.2017 10:01

Ответы (2)


0 плюса

311 Репутация автора

У меня была похожая проблема, и мне удалось решить ее с помощью AspectJ:

https://github.com/mdanetzky/tour-of-heroes-java

Кроме того - мне потребовалось некоторое время, чтобы выяснить, что моя IDEA не перестраивала аспекты должным образом, поэтому, возможно, стоит попытаться очистить / перестроить проект, прежде чем пытаться принять более радикальные меры.

Автор: Matthias Danetzky Размещён: 11.03.2017 10:35

4 плюса

35583 Репутация автора

Решение

Вы допустили типичную ошибку новичков в Spring AOP: вы забыли, что AOP на основе прокси работает, только если прокси-методы вызываются извне, а не через this(избегая прокси). Но внутренний звонок inTry()такой же как this.inTry(). Таким образом, аспект никогда не срабатывает, inTryи вы должны изменить свой код следующим образом:

package spring.aop;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController("/")
public class HomeController {

    static int counter = 0;

    @RequestMapping
    @RetryOnFailure(attempts = 3, delay = 2, unit = TimeUnit.SECONDS)
    public String index() {
        throw new RuntimeException("Exception in try " + ++counter);
    }
}

Я также немного изменил аспект, чтобы

  • избежать отражения и связать аннотацию с параметром консультации непосредственно с помощью @annotation(),
  • войти в точку соединения, когда совет срабатывает и
  • верните «OK» при попытке № 3 (просто для удовольствия, не обязательно).
package spring.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public final class MethodRepeater {

    @Around("execution(* spring.aop..*(..)) && @annotation(retryOnFailure)")
    public Object wrap(final ProceedingJoinPoint joinPoint, RetryOnFailure retryOnFailure) throws Throwable {
        System.out.println(joinPoint);
        return proceed(joinPoint, retryOnFailure);
    }

    private Object proceed(ProceedingJoinPoint joinPoint, RetryOnFailure retryOnFailure) throws Throwable {
        int attempt = 1;
        while (true) {
            try {
                return joinPoint.proceed();
            } catch (final Throwable ex) {
                System.out.println("Try #" + attempt + " failed: " + ex);
                if (++attempt >= retryOnFailure.attempts())
                    return "OK";
                if (retryOnFailure.delay() > 0L)
                    retryOnFailure.unit().sleep(retryOnFailure.delay());
            }
        }
    }
}

Теперь это работает, и журнал консоли говорит:

execution(String spring.aop.HomeController.index())
Try #1 failed: java.lang.RuntimeException: Exception in try 1
Try #2 failed: java.lang.RuntimeException: Exception in try 2
Автор: kriegaex Размещён: 11.03.2017 12:55
Вопросы из категории :
32x32