Spring Proxy

Spring proxy — объект-обёртка, через который контейнер перехватывает вызов метода и применяет advice: транзакцию, безопасность, кэширование или пользовательский аспект.

caller → proxy → interceptor chain → target method

Виды

  • JDK dynamic proxy реализует интерфейсы целевого объекта;
  • class-based proxy создаёт подкласс и может проксировать класс без интерфейса.

Конкретный выбор зависит от конфигурации и возможностей класса. final-класс или final-метод нельзя переопределить class-based proxy. Приватный метод не является внешней точкой вызова.

Self-invocation

public void importAll() {
    saveOne(); // вызов через this, proxy не участвует
}
 
@Transactional
public void saveOne() {}

Аннотация на saveOne не создаст новую interceptor-границу при таком вызове. Решения:

  • вынести операцию в другой bean;
  • перенести аннотацию на внешнюю точку;
  • использовать программный API;
  • применять weaving только при осознанной необходимости.

Идентичность и тип

Инъекция обычно получает proxy, а не target. Проверка точного класса, прямой new и нестандартный equals могут дать сюрпризы. Объект, созданный вручную, контейнером не проксируется.

Вопросы для повторения

  1. Где выполняется @Transactional? В interceptor proxy вокруг внешнего вызова.
  2. Почему вызов через this обходится без advice? Он не проходит через proxy-ссылку.
  3. Чем JDK proxy отличается от class proxy? Первый реализует интерфейс, второй наследует класс.
  4. Можно ли проксировать private-метод? Не обычным Spring proxy.
  5. Почему new Service() не даёт транзакций? Такой объект не создан и не обёрнут контейнером.

Связано: Spring AOP, Transactional, Аннотация Cacheable.