middle
Какие типы Advice существуют в Spring AOP?
В Spring AOP существует пять типов advice, определяющих, когда выполняется дополнительная логика относительно целевого метода.
| Тип | Когда выполняется |
|---|---|
| @Before | До вызова метода |
| @AfterReturning | После успешного возврата метода |
| @AfterThrowing | После выброса исключения |
| @After | Всегда после метода (аналог finally) |
| @Around | Оборачивает вызов целиком (самый мощный) |
Порядок выполнения
@Around (начало) -> @Before -> метод -> @AfterReturning / @AfterThrowing -> @After -> @Around (конец)
Примеры всех типов advice
@Before("execution(* com.example.service.*.*(..))")
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("До вызова: " + joinPoint.getSignature().getName());
}
@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
System.out.println("Метод вернул: " + result);
}
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")
public void afterThrowingAdvice(JoinPoint joinPoint, Exception ex) {
System.out.println("Исключение: " + ex.getMessage());
}
@After("execution(* com.example.service.*.*(..))")
public void afterAdvice(JoinPoint joinPoint) {
System.out.println("Метод завершён (в любом случае)");
}
@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
try {
Object result = pjp.proceed(); // вызов оригинального метода
return result;
} finally {
long elapsed = System.currentTimeMillis() - start;
System.out.println(pjp.getSignature().getName() + " выполнен за " + elapsed + " мс");
}
}
Практический пример – замер времени через собственную аннотацию
Пример
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Timed { }
@Aspect
@Component
public class TimingAspect {
@Around("@annotation(Timed)")
public Object measureTime(ProceedingJoinPoint pjp) throws Throwable {
long start = System.nanoTime();
Object result = pjp.proceed();
long duration = (System.nanoTime() - start) / 1_000_000;
log.info("{}.{} выполнен за {} мс",
pjp.getTarget().getClass().getSimpleName(),
pjp.getSignature().getName(), duration);
return result;
}
}
На собеседовании: важно знать все 5 типов и порядок их выполнения. Частая ошибка в
@Around– забыть вызватьpjp.proceed()(метод не выполнится) или забыть вернуть результатproceed()(метод вернёт null).