Ответ
Прокси создается один раз, во время инициализации бина в контексте Spring, до того как бин будет готов к использованию.
Процесс создания проксированного бина:
- Spring создает целевой экземпляр бина (ваш класс
@Service). - Если бин (или его методы) помечен аннотацией
@Transactional, механизм AOP (BeanPostProcessor) определяет необходимость в прокси. - Создается динамический прокси-обертка (средствами JDK или CGLIB), которая содержит логику управления транзакциями.
- В контекст подставляется не исходный бин, а его прокси. Все вызовы извне идут через него.
Пример и визуализация:
@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).