Какие знаешь виды прокси?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Виды прокси в Java
Proxy — это паттерн проектирования, который предоставляет заменитель или placeholder для другого объекта. Прокси позволяет контролировать доступ к объекту, отложить его создание, добавить дополнительную логику. Я активно использую прокси в различных сценариях.
1. Protection Proxy (Прокси защиты)
Контролирует доступ к объекту на основе прав доступа:
// Интерфейс оригинального объекта
public interface DataService {
String getData();
void updateData(String data);
}
// Реальная реализация
public class RealDataService implements DataService {
@Override
public String getData() {
return "sensitive data";
}
@Override
public void updateData(String data) {
System.out.println("Updated: " + data);
}
}
// Protection Proxy
public class ProtectionProxy implements DataService {
private final DataService realService;
private final User currentUser;
public ProtectionProxy(DataService realService, User currentUser) {
this.realService = realService;
this.currentUser = currentUser;
}
@Override
public String getData() {
if (currentUser.hasPermission("READ")) {
return realService.getData();
}
throw new AccessDeniedException("User has no READ permission");
}
@Override
public void updateData(String data) {
if (currentUser.hasPermission("WRITE")) {
realService.updateData(data);
} else {
throw new AccessDeniedException("User has no WRITE permission");
}
}
}
// Использование
DataService service = new ProtectionProxy(
new RealDataService(),
currentUser
);
2. Virtual Proxy (Ленивое создание объекта)
Отлаживает создание дорогостоящего объекта до момента его использования:
public interface Image {
void display();
}
public class RealImage implements Image {
private String filename;
public RealImage(String filename) {
System.out.println("Loading image from disk: " + filename);
this.filename = filename;
}
@Override
public void display() {
System.out.println("Displaying: " + filename);
}
}
// Virtual Proxy — создаёт RealImage только при display()
public class ImageProxy implements Image {
private String filename;
private RealImage realImage;
public ImageProxy(String filename) {
this.filename = filename; // Только сохраняем имя
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(filename); // Ленивое создание
}
realImage.display();
}
}
// Использование
Image image = new ImageProxy("photo.jpg");
// RealImage ещё не загружена
image.display(); // Теперь загружается
3. Remote Proxy (Прокси удалённого объекта)
Представляет объект, находящийся на удалённой машине:
public interface UserService {
User getUserById(Long id);
void updateUser(User user);
}
// Прокси, который обращается к удалённому сервису
public class RemoteUserServiceProxy implements UserService {
private final String remoteServiceUrl;
private final RestTemplate restTemplate;
public RemoteUserServiceProxy(String url, RestTemplate restTemplate) {
this.remoteServiceUrl = url;
this.restTemplate = restTemplate;
}
@Override
public User getUserById(Long id) {
try {
String url = remoteServiceUrl + "/users/" + id;
return restTemplate.getForObject(url, User.class);
} catch (RestClientException e) {
throw new ServiceUnavailableException("User service is unavailable", e);
}
}
@Override
public void updateUser(User user) {
String url = remoteServiceUrl + "/users/" + user.getId();
restTemplate.put(url, user);
}
}
// Использование
UserService service = new RemoteUserServiceProxy(
"http://remote-server:8080/api",
new RestTemplate()
);
User user = service.getUserById(1L);
4. Logging/Caching Proxy
Добавляет логирование или кэширование к существующему объекту:
public class CachingCalculatorProxy implements Calculator {
private final Calculator realCalculator;
private final Map<String, Integer> cache = new HashMap<>();
public CachingCalculatorProxy(Calculator realCalculator) {
this.realCalculator = realCalculator;
}
@Override
public int calculate(int a, int b, String operation) {
String key = a + ":" + b + ":" + operation;
// Проверка кэша
if (cache.containsKey(key)) {
System.out.println("Cache hit for " + key);
return cache.get(key);
}
// Вычисление
int result = realCalculator.calculate(a, b, operation);
cache.put(key, result);
return result;
}
}
// Логирующий прокси
public class LoggingCalculatorProxy implements Calculator {
private final Calculator realCalculator;
private static final Logger logger = LoggerFactory.getLogger(LoggingCalculatorProxy.class);
public LoggingCalculatorProxy(Calculator realCalculator) {
this.realCalculator = realCalculator;
}
@Override
public int calculate(int a, int b, String operation) {
logger.info("Calculating: {} {} {}", a, operation, b);
long startTime = System.currentTimeMillis();
int result = realCalculator.calculate(a, b, operation);
long duration = System.currentTimeMillis() - startTime;
logger.info("Result: {}, Duration: {}ms", result, duration);
return result;
}
}
5. Dynamic Proxy (Динамический прокси)
Создание прокси в runtime с помощью Java Reflection API:
public class DynamicProxyExample {
public static void main(String[] args) {
UserService realService = new RealUserService();
// Создание динамического прокси
UserService proxyService = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// До вызова
System.out.println("Before: " + method.getName());
long startTime = System.currentTimeMillis();
// Вызов реального метода
Object result = method.invoke(realService, args);
// После вызова
long duration = System.currentTimeMillis() - startTime;
System.out.println("After: " + method.getName() +
" (took " + duration + "ms)");
return result;
}
}
);
// Использование прокси
proxyService.getUserById(1L);
}
}
public interface UserService {
User getUserById(Long id);
}
public class RealUserService implements UserService {
@Override
public User getUserById(Long id) {
return new User(id, "John Doe");
}
}
6. Spring AOP Proxy
Spring использует прокси для реализации AOP (Aspect-Oriented Programming):
// Aspect для логирования
@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.example.service..*(..))")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
System.out.println("Executing: " + joinPoint.getSignature().getName());
Object result = joinPoint.proceed(); // Вызов реального метода
long duration = System.currentTimeMillis() - startTime;
System.out.println("Execution time: " + duration + "ms");
return result;
}
}
// Сервис
@Service
public class OrderService {
// Spring автоматически создаст прокси
public void createOrder(Order order) {
System.out.println("Creating order...");
}
}
7. Lazy Initialization Proxy
Для инициализации сложных зависимостей:
public class DatabaseProxy implements Database {
private Database realDatabase;
private String connectionString;
public DatabaseProxy(String connectionString) {
this.connectionString = connectionString;
// БД ещё не инициализирована
}
private Database getDatabase() {
if (realDatabase == null) {
System.out.println("Initializing database connection...");
realDatabase = new RealDatabase(connectionString);
}
return realDatabase;
}
@Override
public ResultSet query(String sql) {
return getDatabase().query(sql);
}
}
8. Copy-On-Write Proxy
Для оптимизации памяти при копировании объектов:
public class CopyOnWriteDocument implements Document {
private Document original;
private Document copy;
public CopyOnWriteDocument(Document original) {
this.original = original;
}
@Override
public String getContent() {
// Просто читаем из оригинала
return original.getContent();
}
@Override
public void setContent(String content) {
// Копируем только при модификации
if (copy == null) {
copy = new RealDocument(original.getContent());
}
copy.setContent(content);
}
}
Сравнение видов прокси
| Тип | Назначение | Когда использовать |
|---|---|---|
| Protection | Контроль доступа | Защита конфиденциальных данных |
| Virtual | Ленивое создание | Дорогостоящие объекты |
| Remote | Удалённые объекты | Распределённые системы |
| Logging/Caching | Добавление логики | Мониторинг, оптимизация |
| Dynamic | Runtime прокси | Когда тип неизвестен заранее |
| Spring AOP | Aspect-oriented | Cross-cutting concerns |
| Copy-On-Write | Оптимизация памяти | Многопоточные сценарии |
Мой практический опыт
- Использовал Spring AOP для логирования и мониторинга в production системах
- Реализовал Virtual Proxy для инициализации тяжёлых ресурсов
- Применял Dynamic Proxy для generic обработки методов
- Использовал Remote Proxy для интеграции микросервисов
- Implement Caching Proxy для оптимизации производительности
Прокси — это мощный паттерн, который позволяет добавлять функциональность без изменения оригинального класса.