Gymterview
junior

Что такое паттерн Proxy?

Proxy – паттерн, предоставляющий объект-заместитель, который контролирует доступ к другому объекту.

Аналогия из жизни: Proxy – как секретарь руководителя. Все звонки идут через секретаря, который решает: передать ли звонок, записать сообщение, отказать или добавить информацию к запросу.

Статический Proxy -- пример
interface UserService {
    User findById(Long id);
}

class UserServiceImpl implements UserService {
    public User findById(Long id) {
        return database.query("SELECT * FROM users WHERE id = ?", id);
    }
}

// Proxy: кэширование
class CachingUserServiceProxy implements UserService {
    private final UserService delegate;
    private final Map<Long, User> cache = new ConcurrentHashMap<>();

    CachingUserServiceProxy(UserService delegate) { this.delegate = delegate; }

    public User findById(Long id) {
        return cache.computeIfAbsent(id, delegate::findById);
    }
}

// Proxy: логирование
class LoggingUserServiceProxy implements UserService {
    private final UserService delegate;

    public User findById(Long id) {
        log.info("findById called with id={}", id);
        User result = delegate.findById(id);
        log.info("findById returned: {}", result);
        return result;
    }
}
JDK Dynamic Proxy
UserService proxy = (UserService) Proxy.newProxyInstance(
    UserService.class.getClassLoader(),
    new Class[]{UserService.class},
    (proxyObj, method, args) -> {
        log.info("Вызов: {}", method.getName());
        long start = System.nanoTime();
        Object result = method.invoke(realService, args);
        log.info("Время: {} мс", (System.nanoTime() - start) / 1_000_000);
        return result;
    }
);

Виды Proxy

Вид Назначение Пример
Virtual Proxy Ленивая загрузка Hibernate Lazy Loading
Protection Proxy Контроль доступа Spring Security @PreAuthorize
Caching Proxy Кэширование Spring @Cacheable
Logging Proxy Логирование Spring AOP

Важное

  • Spring AOP построен на Proxy: @Transactional, @Cacheable, @Async работают через прокси
  • JDK Dynamic Proxy – для интерфейсов; CGLIB – для классов (наследование)

Частые ошибки

  • Вызов метода внутри того же класса – Spring Proxy не перехватывает self-invocation: this.method() обходит прокси
  • Proxy на final-класс – CGLIB не может создать прокси для final-класса

Как используется в 2026

  • Spring AOP: @Transactional, @Cacheable, @Async, @PreAuthorize – всё через Proxy
  • Hibernate Lazy Loading – Proxy для отложенной загрузки сущностей

На собеседовании: ключевой вопрос – self-invocation в Spring. Объясните, почему this.method() обходит прокси и как это решить (через AopContext или вынос в другой бин). Частая ошибка – не знать разницу между JDK Dynamic Proxy и CGLIB.