Ответ
Spring Proxy (прокси) — это объект, который Spring Framework динамически создает вокруг целевого бина (обычно @Component, @Service, @Repository), чтобы добавить к нему дополнительное поведение (сквозную функциональность) без изменения его исходного кода. Это основа механизма AOP (Aspect-Oriented Programming) в Spring.
Основная цель: Разделение основного бизнес-логики (core concern) и сквозной функциональности (cross-cutting concern).
Типичные сценарии использования прокси в Spring:
- Декларативное управление транзакциями (
@Transactional). - Кеширование (
@Cacheable,@CacheEvict). - Безопасность и проверка прав доступа (
@Secured,@PreAuthorize). - Логирование, мониторинг, обработка исключений.
- Ленивая загрузка (
@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:
-
JDK Dynamic Proxy (по умолчанию для интерфейсов):
- Создается, если бин реализует хотя бы один интерфейс.
- Прокси реализует те же интерфейсы, что и целевой объект.
- Ограничение: Вызовы методов, происходящие внутри самого бина (например, вызов одного
@Transactionalметода из другого метода того же бина), не проходят через прокси и, следовательно, не обрабатываются AOP.
-
CGLIB Proxy (для классов):
- Создается, если бин не реализует интерфейсы (или задано явное указание).
- Работает путем наследования от целевого класса и переопределения его методов.
- Требует: Класс и его методы не должны быть
final.
Настройка: Режим проксирования задается аннотацией @EnableAspectJAutoProxy(proxyTargetClass = true) для принудительного использования CGLIB.