Перейти к основному содержимому

Паттерн "Заместитель" (Proxy) в Java — доступ, кэш и lazy loading

Разработчику Архитектору

Обзор — в структурных паттернах. Здесь — Proxy на Java: объект с тем же интерфейсом, что и "настоящий" сервис, но с перехватом до/после вызова.

Загрузка редактора схем…

Задача паттерна

Proxy подменяет реальный объект суррогатом с тем же контрактом. Клиент вызывает прокси; прокси может проверить права, закэшировать ответ или отложить создание тяжёлого объекта.


Пример — документы с доступом и кэшем

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

interface DocumentService {
String loadDocument(String docId);
}

class RealDocumentService implements DocumentService {
@Override
public String loadDocument(String docId) {
System.out.println("Загрузка из хранилища: " + docId);
return "Содержимое документа " + docId;
}
}

final class SecurityContext {
private static final ThreadLocal<String> currentRole = new ThreadLocal<>();

static void setCurrentRole(String role) {
currentRole.set(role);
}

static String getCurrentRole() {
return currentRole.get();
}
}

class DocumentServiceProxy implements DocumentService {
private final RealDocumentService realService = new RealDocumentService();
private final Map<String, String> cache = new HashMap<>();
private final Set<String> allowedRoles;

DocumentServiceProxy(Set<String> allowedRoles) {
this.allowedRoles = allowedRoles;
}

@Override
public String loadDocument(String docId) {
String role = SecurityContext.getCurrentRole();
if (!allowedRoles.contains(role)) {
throw new SecurityException("Нет доступа");
}
return cache.computeIfAbsent(docId, realService::loadDocument);
}
}
SecurityContext.setCurrentRole("ADMIN");
DocumentService service = new DocumentServiceProxy(Set.of("ADMIN", "EDITOR"));
String doc = service.loadDocument("report-2026");

Виды прокси в Java

ТипПример
ProtectionПроверка роли перед вызовом (Spring Security)
CachingcomputeIfAbsent в примере выше
LazyHibernate lazy-прокси сущности (JPA)
RemoteRMI, gRPC-клиент как удалённый суррогат
Logging / metricsSpring AOP @Around

JDK динамические прокси (java.lang.reflect.Proxy) и ByteBuddy/CGLIB в Spring создают прокси во время выполнения без ручного класса-обёртки.


Proxy и Decorator

ProxyDecorator
ФокусКонтроль доступа и жизненного циклаДобавление поведения
КлиентМожет не знать о существовании real subjectОжидает цепочку обёрток
ПримерLazy load, securitynew BufferedInputStream(new FileInputStream(...))

Когда применять и риски

Прокси уместен, когда нужен прозрачный контроль без изменения клиентского кода.

Несколько слоёв прокси (AOP + security + cache) усложняют отладку и добавляют задержку — логируйте цепочку перехватчиков в dev-среде.


См. также

См. также

Другие статьи этого же раздела в боковом меню (как на странице "О разделе").