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.