Какие механизмы проксирования доступны в Spring Framework?

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

Ответ

Spring Framework поддерживает три основных механизма проксирования, каждый со своей областью применения.

1. JDK Dynamic Proxy (Proxy на основе интерфейсов)

  • Принцип работы: Использует встроенные возможности Java (java.lang.reflect.Proxy). Создает прокси-объект, реализующий те же интерфейсы, что и целевой объект.
  • Когда используется: По умолчанию, если бин реализует хотя бы один интерфейс.
  • Ограничение: Не может проксировать классы, не имеющие интерфейсов, или вызовы методов, объявленных в самом классе (не в интерфейсе).
public interface UserService {
    void createUser();
}

@Service
public class UserServiceImpl implements UserService {
    @Override
    @Transactional // Для этого вызова будет создан JDK Dynamic Proxy
    public void createUser() {
        // логика
    }
}

2. CGLIB Proxy (Proxy на основе наследования)

  • Принцип работы: Создает подкласс целевого класса во время выполнения (байт-кодовая генерация) и переопределяет его методы.
  • Когда используется: Когда целевой класс не реализует интерфейсы (например, конкретный класс). Для активации необходимо установить proxyTargetClass = true.
  • Ограничение: Не может переопределить final методы или проксировать final классы.
@Service
public class ConcreteService { // Нет интерфейса
    @Transactional // Для этого вызова будет создан CGLIB Proxy
    public void process() {
        // логика
    }
}

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // Принудительное использование CGLIB
public class AppConfig {}

3. AspectJ Compile-time/Load-time Weaving

  • Принцип работы: Модифицирует байт-код класса на этапе компиляции или загрузки в JVM. Не использует стандартные прокси Spring.
  • Когда используется: Для наиболее сложных сценариев, где требуется проксирование private методов, конструкторов или полей, а также для максимальной производительности.
  • Ограничение: Требует дополнительной настройки сборки (AspectJ compiler) или агента загрузки.

Сравнение:

  • JDK Proxy: Быстрее создается, вызовы через интерфейс медленнее. Стандартная Java.
  • CGLIB: Медленнее создается, вызовы методов быстрее. Требует библиотеки CGLIB в classpath.
  • AspectJ: Наибольшая гибкость и производительность во время выполнения, но сложнее в настройке.