← Назад к вопросам

Что такое advice?

2.0 Middle🔥 141 комментариев
#Spring Framework

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Advice

Advice — это ключевая концепция в Aspect-Oriented Programming (AOP), которая определяет действие, выполняемое аспектом в определённой точке программы. Advice содержит код, который должен выполниться в момент, когда программа достигает определённого joinpoint'а (точки присоединения).

Контекст: AOP в Spring

Spring AOP использует advice для разделения cross-cutting concerns (перекрёстные проблемы) — функциональность, которая применяется ко многим местам в приложении: логирование, безопасность, кэширование, обработка транзакций.

Типы Advice

Before Advice — выполняется ПЕРЕД выполнением joinpoint'а.

@Aspect
@Component
public class LoggingAspect {
    
    @Before("execution(* com.example.service.*.get*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Метод вызван: " + joinPoint.getSignature().getName());
    }
}

After Returning Advice — выполняется ПОСЛЕ успешного завершения joinpoint'а.

@AfterReturning(pointcut = "execution(* com.example.service.*.get*(..))", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
    System.out.println("Метод вернул: " + result);
}

After Throwing Advice — выполняется, когда joinpoint выбросит исключение.

@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "error")
public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
    System.out.println("Исключение в методе " + joinPoint.getSignature().getName());
    error.printStackTrace();
}

After Advice — выполняется ПОСЛЕ выполнения joinpoint'а, независимо от результата (успех или ошибка).

@After("execution(* com.example.service.*.save*(..))") 
public void logAfter(JoinPoint joinPoint) {
    System.out.println("Метод завершен: " + joinPoint.getSignature().getName());
}

Around Advice — самый мощный тип, выполняется ДО И ПОСЛЕ joinpoint'а, полностью контролирует выполнение.

@Around("execution(* com.example.service.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("До вызова: " + joinPoint.getSignature().getName());
    
    try {
        Object result = joinPoint.proceed(); // Вызов исходного метода
        System.out.println("После успешного вызова");
        return result;
    } catch (Exception e) {
        System.out.println("Ошибка при вызове");
        throw e;
    }
}

Joinpoint и Pointcut

Joinpoint — это точка в коде, где может быть применён advice. Обычно это:

  • Вызов метода
  • Доступ к полю
  • Создание объекта
  • Обработка исключения

Pointcut — выражение, описывающее, к каким joinpoint'ам применить advice.

// Выполнение любого метода в пакете com.example.service
@Before("execution(* com.example.service.*.*(..))") 

// Методы с аннотацией @Transactional
@Before("@annotation(org.springframework.transaction.annotation.Transactional)")

// Методы, начинающиеся с 'get' и принимающие Long параметр
@Before("execution(* get*(..)) && args(id)")
public void logWithId(Long id) { }

Практический пример: Аспект для кэширования

@Aspect
@Component
public class CachingAspect {
    
    private Map<String, Object> cache = new ConcurrentHashMap<>();
    
    @Around("@annotation(com.example.annotation.Cacheable)")
    public Object cacheAround(ProceedingJoinPoint joinPoint) throws Throwable {
        String key = generateCacheKey(joinPoint);
        
        // Проверяем кэш
        if (cache.containsKey(key)) {
            System.out.println("Возврат из кэша: " + key);
            return cache.get(key);
        }
        
        // Если в кэше нет, вызываем метод
        Object result = joinPoint.proceed();
        
        // Сохраняем в кэш
        cache.put(key, result);
        System.out.println("Сохранено в кэш: " + key);
        
        return result;
    }
    
    private String generateCacheKey(ProceedingJoinPoint joinPoint) {
        return joinPoint.getSignature().getName() + 
               Arrays.toString(joinPoint.getArgs());
    }
}

Использование в бизнес-коде

@Service
public class UserService {
    
    @Before("execution(* save(..))")
    public void validateBeforeSave() {
        System.out.println("Проверка данных перед сохранением");
    }
    
    public void save(User user) {
        // Сохранение пользователя
        System.out.println("Сохраняю пользователя: " + user.getName());
    }
}

Преимущества использования Advice

  • Разделение ответственности — cross-cutting concerns отделены от бизнес-логики
  • Переиспользуемость — один advice применяется ко многим методам
  • Чистота кода — бизнес-логика не захламляется служебным кодом
  • Централизованное управление — все правила в одном месте

Когда использовать разные типы Advice

  • Before — валидация входных данных
  • After Returning — логирование успешных результатов
  • After Throwing — обработка ошибок и логирование исключений
  • After — cleanup ресурсов
  • Around — профилирование, кэширование, полный контроль выполнения

Advice — это мощный инструмент для создания чистого, поддерживаемого кода в Java-приложениях.

Что такое advice? | PrepBro