Когда Spring создает прокси для бина с аннотацией @Transactional?

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

Ответ

Прокси создается один раз, во время инициализации бина в контексте Spring, до того как бин будет готов к использованию.

Процесс создания проксированного бина:

  1. Spring создает целевой экземпляр бина (ваш класс @Service).
  2. Если бин (или его методы) помечен аннотацией @Transactional, механизм AOP (BeanPostProcessor) определяет необходимость в прокси.
  3. Создается динамический прокси-обертка (средствами JDK или CGLIB), которая содержит логику управления транзакциями.
  4. В контекст подставляется не исходный бин, а его прокси. Все вызовы извне идут через него.

Пример и визуализация:

@Service
public class UserService {
    @Transactional
    public void createUser(String name) {
        // Бизнес-логика
        userRepository.save(new User(name));
    }
}

// При вызове из другого бина:
userService.createUser("Alice");

// Фактическая последовательность выполнения:
// 1. Вызов идет на ПРОКСИ userService
// 2. Прокси открывает транзакцию (session.beginTransaction())
// 3. Прокси вызывает ЦЕЛЕВОЙ МЕТОД createUser() на реальном объекте UserService
// 4. После успешного выполнения прокси фиксирует транзакцию (commit)
// 5. В случае исключения - откатывает (rollback)

Критически важные следствия:

  • Самовызовы (this.method()) внутри бина не проходят через прокси, поэтому @Transactional на таком методе не сработает. Нужно инжектировать сам бин или использовать AopContext.
  • Прокси создается на уровне контейнера Spring, а не при каждом вызове метода.
  • Выбор между JDK Dynamic Proxy (если бин реализует интерфейс) и CGLIB (если нет) можно контролировать через @EnableTransactionManagement(proxyTargetClass = true).