Что такое Spring Proxy и для чего он используется?

«Что такое Spring Proxy и для чего он используется?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Spring Proxy (прокси) — это объект, который Spring Framework динамически создает вокруг целевого бина (обычно @Component, @Service, @Repository), чтобы добавить к нему дополнительное поведение (сквозную функциональность) без изменения его исходного кода. Это основа механизма AOP (Aspect-Oriented Programming) в Spring.

Основная цель: Разделение основного бизнес-логики (core concern) и сквозной функциональности (cross-cutting concern).

Типичные сценарии использования прокси в Spring:

  1. Декларативное управление транзакциями (@Transactional).
  2. Кеширование (@Cacheable, @CacheEvict).
  3. Безопасность и проверка прав доступа (@Secured, @PreAuthorize).
  4. Логирование, мониторинг, обработка исключений.
  5. Ленивая загрузка (@Lazy).

Как это работает? Когда вы вызываете метод бина, который помечен аннотацией, требующей прокси (например, @Transactional), вы на самом деле вызываете метод не исходного объекта, а его прокси-обертку. Прокси выполняет необходимые действия до и после вызова целевого метода.

Пример: Прокси для @Transactional

@Service
public class BankService {

    @Transactional // Аннотация, активирующая создание прокси
    public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
        // 1. Прокси ОТКРЫВАЕТ транзакцию
        // 2. Вызывает ЭТОТ метод (целевой)
        debitAccount(fromId, amount);
        creditAccount(toId, amount);
        // 3. Прокси КОММИТИТ транзакцию (или откатывает при исключении)
    }

    private void debitAccount(Long id, BigDecimal amount) { /* ... */ }
    private void creditAccount(Long id, BigDecimal amount) { /* ... */ }
}

Типы прокси в Spring:

  1. JDK Dynamic Proxy (по умолчанию для интерфейсов):

    • Создается, если бин реализует хотя бы один интерфейс.
    • Прокси реализует те же интерфейсы, что и целевой объект.
    • Ограничение: Вызовы методов, происходящие внутри самого бина (например, вызов одного @Transactional метода из другого метода того же бина), не проходят через прокси и, следовательно, не обрабатываются AOP.
  2. CGLIB Proxy (для классов):

    • Создается, если бин не реализует интерфейсы (или задано явное указание).
    • Работает путем наследования от целевого класса и переопределения его методов.
    • Требует: Класс и его методы не должны быть final.

Настройка: Режим проксирования задается аннотацией @EnableAspectJAutoProxy(proxyTargetClass = true) для принудительного использования CGLIB.