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

Коли Spring створює proxy?

4. Не проксируйте final класи/методи 5. Мінімізуйте кількість проксі 6. AopUtils → для перевірки проксі

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

🟢 Junior Level

Spring створює проксі, коли бачить спеціальні анотації:

Анотація Що додає проксі
@Transactional Управління транзакціями
@Async Асинхронне виконання
@Cacheable Кешування результатів
@PreAuthorize Перевірка прав доступу
@Service
public class MyService {

    @Transactional  // ← Проксі для транзакцій
    public void save() { }

    @Async  // ← Проксі для асинхронності
    public CompletableFuture<Void> process() { }
}

🟡 Middle Level

Функціональні тригери

@Transactional:

Proxy → відкриває транзакцію → викликає метод → commit/rollback

@Async:

Proxy → передає завдання в TaskExecutor → повертає Future одразу

@Cacheable:

Proxy → перевіряє кеш → якщо є → повертає з кешу
     → якщо немає → викликає метод → зберігає в кеш

Scoped Proxies:

@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
// → Проксі шукає актуальний бін в RequestContextHolder

Механізм створення

BeanPostProcessor.postProcessAfterInitialization():
  → AnnotationAwareAspectJAutoProxyCreator сканує бін
  → Знайшов анотацію → створює проксі
  → Проксі замінює оригінальний бін в контексті

🔴 Senior Level

AnnotationAwareAspectJAutoProxyCreator

Головний BPP для створення проксі:
  1. Сканує усі анотації та @Aspect
  2. Для кожного біна перевіряє Pointcut
  3. Якщо підходить → створює проксі
  4. Проксі йде далі по ланцюжку BPP

Уникнення зайвих проксі

Проксі = overhead (пам'ять + CPU)
→ Не ставте @Transactional на методи, які лише читають і не потребують консистентного знімку даних. Якщо транзакція потрібна, використовуйте `readOnly = true` для оптимізації Hibernate (skip dirty checking).
→ Проксі створюється на ВЕСЬ бін, навіть якщо одна анотація

Production Experience

Реальний сценарій: зайвий проксі

Кожен проксі — додатковий об'єкт в пам'яті і невеликий overhead на виклик (порядку наносекунд). При великій кількості бінів це підсумовується.

Рішення: прибрали @Transactional з read методів
→ Менше проксі, менше overhead

Best Practices

  1. @Transactional → лише де потрібно
  2. @Async → обережно, проксі на весь бін
  3. Scoped Proxy → для web scope в Singleton
  4. Не проксируйте final класи/методи
  5. Мінімізуйте кількість проксі
  6. AopUtils → для перевірки проксі

Резюме для Senior

  • Проксі створюється при @Transactional, @Async, @Cacheable
  • BPP → postProcessAfterInitialization
  • Scoped Proxy → для web scope в Singleton
  • Кожен проксі = пам’ять + CPU overhead
  • final → не проксирується
  • AnnotationAwareAspectJAutoProxyCreator → головний творець

🎯 Шпаргалка для співбесіди

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

  • Проксі створюється за наявності @Transactional, @Async, @Cacheable, @PreAuthorize
  • Механізм: AnnotationAwareAspectJAutoProxyCreator (BeanPostProcessor) в postProcessAfterInitialization()
  • Scoped Proxy (@Scope з proxyMode) — створює проксі для web scope в Singleton-бінах
  • Кожен проксі = невелика пам’ять + CPU overhead (наносекунди на виклик)
  • Spring сканує усі анотації та @Aspect, перевіряє Pointcut, створює проксі
  • @Transactional на read-методах без потреби — зайвий overhead — використовуйте readOnly = true

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

  • Який компонент відповідає за створення проксі? → AnnotationAwareAspectJAutoProxyCreator (BPP)
  • Коли створюється Scoped Proxy? → При @Scope(value="request", proxyMode=TARGET_CLASS)
  • Чи можна уникнути створення проксі? → Так, не ставити анотації де не потрібні
  • Як Spring вирішує, який тип проксі створити? → proxy-target-class=true → CGLIB, false + є інтерфейс → JDK Proxy

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

  • «Проксі створюється для кожного біна» — лише з AOP-анотаціями
  • «@Transactional на read-методах завжди обов’язковий» — зайвий overhead без потреби
  • «Проксі додає помітну затримку» — наносекунди
  • «final-класи проксируються через CGLIB» — не проксируються

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

  • [[11. Які scope існують в Spring]]
  • [[13. Що таке proxy в Spring]]
  • [[15. Що таке AOP (Aspect-Oriented Programming)]]
  • [[17. Що робить анотація @Transactional]]