Питання 15 · Розділ 5

Що таке AOP (Aspect-Oriented Programming)?

4. Статичні Pointcut → швидше динамічних 5. Уникайте стану в аспектах (Singleton!) 6. @Around → не забудьте pjp.proceed()

Мовні версії: English Russian Ukrainian

🟢 Junior Level

AOP — спосіб додати загальну функціональність (логування, транзакції) до багатьох класів, не змінюючи їх код.

Проста аналогія: Уявіть, що ви хочете записувати кожен дзвінок у компанії. Замість того щоб просити кожного співробітника вести журнал, ви ставите автоматичний запис усіх дзвінків.

// Без AOP:
public void save() {
    log.info("Початок");  // Повторюється скрізь
    repository.save(entity);
    log.info("Кінець");
}

// З AOP:
@LogExecution  // ← Одна анотація!
public void save() {
    repository.save(entity);
}

Навіщо:

  • Прибирає дублювання коду
  • Бізнес-логіка окремо, інфраструктура окремо
  • Легко увімкнути/вимкнути

🟡 Middle Level

Spring AOP vs AspectJ

  Spring AOP AspectJ
Як Проксі в рантаймі Зміна байт-коду
Що може Тільки public методи Методи, поля, конструктори
Self-invocation ❌ Не працює ✅ Працює
Складність Простий Складне налаштування

Spring AOP працює тільки з Spring-бінами (виклики через проксі). AspectJ працює з будь-якими об’єктами, т.к. впроваджується на рівні байт-коду (compile-time або load-time weaving).

Терміни AOP

Aspect (Аспект)      = модуль наскрізної логіки
Pointcut (Точка)     = де застосовувати (вираз)
Advice (Порада)      = що робити (логіка)
Join Point (Точка з'єднання) = конкретний метод

Типи Advice

@Before         // До методу
@After          // Після методу (завжди)
@AfterReturning // Після успішного
@AfterThrowing  // При виключенні
@Around         // Замість методу (найпотужніший)

Приклад аспекту

@Aspect
@Component
public class LoggingAspect {

    @Around("@annotation(LogExecution)")
    public Object log(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            return pjp.proceed();  // Виклик оригінального методу
        } finally {
            long duration = System.currentTimeMillis() - start;
            log.info("Виконано за " + duration + "ms");
        }
    }
}

🔴 Senior Level

Interceptor Chain

Виклик методу → ReflectiveMethodInvocation:
  1. SecurityInterceptor → перевірка прав
  2. TransactionInterceptor → транзакція
  3. CacheInterceptor → кеш
  4. LoggingAspect → логування
  5. Target method → ваш код

→ Кожен повертає результат або кидає exception
→ Порядок визначається через @Order

Продуктивність

Оверхед AOP:
  → Створення MethodInvocation об'єкта
  → Прохід по списку інтерцепторів
  → Рефлексія або прямий виклик

→ ~1-5 мкс на виклик
→ У Highload (1M RPS) → помітно!

Spring 6 + Virtual Threads

`synchronized` (ключове слово) в аспектах → Pinning віртуальних потоків!
→ Перевірте, чи не блокують ваші аспекти системні потоки

Production Experience

Повний приклад з Around без proceed() — у файлі [[16. Що таке аспект, advice, pointcut, join point]].

Best Practices

  1. Spring AOP → 95% випадків
  2. AspectJ → приватні методи, поля
  3. @Order → порядок аспектів
  4. Статичні Pointcut → швидше динамічних
  5. Уникайте стану в аспектах (Singleton!)
  6. @Around → не забудьте pjp.proceed()

Резюме для Senior

  • AOP = наскрізна функціональність без дублювання
  • Spring AOP = проксі, AspectJ = байт-код
  • Interceptor Chain → порядок через @Order
  • Оверхед ~1-5 мкс на виклик
  • Pinning → обережно з synchronized в аспектах
  • pjp.proceed() → обов’язково в @Around

🎯 Шпаргалка для інтерв’ю

Обов’язково знати:

  • AOP = наскрізна функціональність (логування, транзакції, кеш) без дублювання коду
  • Spring AOP працює через проксі в рантаймі; AspectJ — через зміну байт-коду
  • Ключові терміни: Aspect (модуль), Pointcut (де), Advice (що), Join Point (конкретний метод)
  • 5 типів Advice: @Before, @After, @AfterReturning, @AfterThrowing, @Around
  • @Around — найпотужніший, але ОБОВ’ЯЗАНИЙ викликати pjp.proceed()
  • Порядок аспектів визначається через @Order
  • Spring AOP: тільки public методи Spring-бінів, self-invocation НЕ працює
  • Оверхед AOP: ~1-5 мкс на виклик, у Highload сумується

Часті уточнюючі запитання:

  • Чому Spring AOP не працює з private-методами? → Проксі перехоплює тільки виклики через proxy object, private-методи недоступні
  • Коли обрати AspectJ замість Spring AOP? → Коли потрібні private-методи, поля, конструктори, або self-invocation
  • @After vs @AfterReturning — в чому різниця? → @After = завжди (як finally), @AfterReturning = тільки при успішному завершенні
  • Що таке ReflectiveMethodInvocation? → Pipeline Spring, послідовно проходить усі interceptors

Червоні прапорці (НЕ говорити):

  • «Spring AOP працює з private-методами» — не працює
  • «@Around без proceed() допустимий» — метод не викличеться взагалі
  • «AOP додає мілісекунди overhead» — наносекунди (1-5 мкс)
  • «Аспект зберігає стан у полях» — аспект = Singleton, не потокобезпечно

Пов’язані теми:

  • [[13. Що таке proxy в Spring]]
  • [[14. Коли Spring створює proxy]]
  • [[16. Що таке аспект, advice, pointcut, join point]]
  • [[17. Що робить анотація @Transactional]]