Назад к вопросам
Middle
95
questionbank

Какие виды прокси-серверов вы знаете?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

В Java существуют следующие виды прокси:

  • Статические (Static Proxy): Реализуется путем создания отдельного класса-обертки, который содержит ссылку на реальный объект и делегирует ему вызовы методов, при этом добавляя собственную логику (например, логгирование, авторизацию).

    // Интерфейс
    interface Service {
        void doSomething();
    }
    
    // Реальный объект
    class RealService implements Service {
        @Override
        public void doSomething() {
            System.out.println("Реальное действие");
        }
    }
    
    // Статический прокси
    class StaticServiceProxy implements Service {
        private final Service realService;
    
        public StaticServiceProxy(Service realService) {
            this.realService = realService;
        }
    
        @Override
        public void doSomething() {
            System.out.println("Перед вызовом реального метода");
            realService.doSomething();
            System.out.println("После вызова реального метода");
        }
    }
    
  • Динамические (Dynamic Proxy): Создаются во время выполнения с использованием Reflection API и требуют, чтобы проксируемый объект реализовывал хотя бы один интерфейс. Позволяют генерировать прокси для множества классов, реализующих один интерфейс, без создания отдельного класса для каждого.

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    // Обработчик вызовов для динамического прокси
    class DynamicServiceInvocationHandler implements InvocationHandler {
        private final Object target; // Целевой объект
    
        public DynamicServiceInvocationHandler(Object target) {
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("Перед вызовом метода " + method.getName());
            Object result = method.invoke(target, args); // Вызов метода целевого объекта
            System.out.println("После вызова метода " + method.getName());
            return result;
        }
    }
    
    // Пример использования (для интерфейса Service из примера статического прокси)
    // Service realService = new RealService();
    // Service proxy = (Service) Proxy.newProxyInstance(
    //     realService.getClass().getClassLoader(),
    //     realService.getClass().getInterfaces(),
    //     new DynamicServiceInvocationHandler(realService));
    // proxy.doSomething();
    
  • CGLIB Proxy: Основан на генерации байткода и не требует реализации интерфейса. Может проксировать конкретные классы (если они не финальные и методы не финальные). Более производительный, чем стандартный динамический прокси в некоторых сценариях.

    // Пример использования CGLIB (требует стороннюю библиотеку)
    // public class RealService {
    //     public void doSomething() {
    //         System.out.println("Реальное действие");
    //     }
    // }
    
    // import net.sf.cglib.proxy.MethodInterceptor;
    // import net.sf.cglib.proxy.MethodProxy;
    // import net.sf.cglib.proxy.Enhancer;
    
    // class CglibServiceInterceptor implements MethodInterceptor {
    //     @Override
    //     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    //         System.out.println("Перед вызовом метода " + method.getName());
    //         Object result = proxy.invokeSuper(obj, args); // Вызов метода суперкласса (оригинального объекта)
    //         System.out.println("После вызова метода " + method.getName());
    //         return result;
    //     }
    // }
    
    // // Пример использования:
    // // Enhancer enhancer = new Enhancer();
    // // enhancer.setSuperclass(RealService.class);
    // // enhancer.setCallback(new CglibServiceInterceptor());
    // // RealService proxy = (RealService) enhancer.create();
    // // proxy.doSomething();
    

Основные различия:

Вид Прокси Требует Интерфейс Генерация Гибкость Производительность Применение
Статический Да Вручную Низкая (для каждого класса) Высокая Простые случаи, когда структура известна
Динамический Да Во время выполнения Высокая (для интерфейсов) Средняя Общая логика для интерфейсов, АОП
CGLIB Нет Во время выполнения Высокая (для классов) Высокая АОП, проксирование классов без интерфейсов