Sobes.tech
Middle

Jakie rodzaje serwerów proxy znasz?

sobes.tech AI

Odpowiedź od AI

W Javie istnieją następujące rodzaje proxy:

  • Proxy statyczne (Static Proxy): Implementuje się je poprzez utworzenie osobnej klasy opakowującej, która zawiera odwołanie do rzeczywistego obiektu i deleguje do niego wywołania metod, dodając własną logikę (np. logowanie, autoryzację).

    // Interfejs
    interface Service {
        void doSomething();
    }
    
    // Rzeczywisty obiekt
    class RealService implements Service {
        @Override
        public void doSomething() {
            System.out.println("Rzeczywiste działanie");
        }
    }
    
    // Proxy statyczne
    class StaticServiceProxy implements Service {
        private final Service realService;
    
        public StaticServiceProxy(Service realService) {
            this.realService = realService;
        }
    
        @Override
        public void doSomething() {
            System.out.println("Przed wywołaniem rzeczywistej metody");
            realService.doSomething();
            System.out.println("Po wywołaniu rzeczywistej metody");
        }
    }
    
  • Proxy dynamiczne (Dynamic Proxy): Tworzone w czasie wykonywania z użyciem Reflection API i wymagają, aby obiekt proxy implementował co najmniej jeden interfejs. Pozwalają generować proxy dla wielu klas implementujących ten sam interfejs, bez konieczności tworzenia osobnej klasy dla każdej z nich.

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    // Obsługa wywołań dla proxy dynamicznego
    class DynamicServiceInvocationHandler implements InvocationHandler {
        private final Object target; // Obiekt docelowy
    
        public DynamicServiceInvocationHandler(Object target) {
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("Przed wywołaniem metody " + method.getName());
            Object result = method.invoke(target, args); // Wywołanie metody obiektu docelowego
            System.out.println("Po wywołaniu metody " + method.getName());
            return result;
        }
    }
    
    // Przykład użycia (dla interfejsu Service z przykładu statycznego proxy)
    // Service realService = new RealService();
    // Service proxy = (Service) Proxy.newProxyInstance(
    //     realService.getClass().getClassLoader(),
    //     realService.getClass().getInterfaces(),
    //     new DynamicServiceInvocationHandler(realService));
    // proxy.doSomething();
    
  • Proxy CGLIB: Oparty na generowaniu kodu bajtowego i nie wymaga implementacji interfejsu. Może proxyować konkretne klasy (jeśli nie są finalne i metody nie są finalne). W niektórych scenariuszach jest wydajniejszy niż standardowy proxy dynamiczny.

    // Przykład użycia CGLIB (wymaga zewnętrznej biblioteki)
    // public class RealService {
    //     public void doSomething() {
    //         System.out.println("Rzeczywiste działanie");
    //     }
    // }
    
    // 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("Przed wywołaniem metody " + method.getName());
    //         Object result = proxy.invokeSuper(obj, args); // Wywołanie metody nadklasy (oryginalnego obiektu)
    //         System.out.println("Po wywołaniu metody " + method.getName());
    //         return result;
    //     }
    // }
    
    // // Przykład użycia:
    // // Enhancer enhancer = new Enhancer();
    // // enhancer.setSuperclass(RealService.class);
    // // enhancer.setCallback(new CglibServiceInterceptor());
    // // RealService proxy = (RealService) enhancer.create();
    // // proxy.doSomething();
    

Główne różnice:

Typ Proxy Wymaga interfejsu Generacja Elastyczność Wydajność Zastosowanie
Statyczny Tak Ręcznie Niska (dla każdej klasy) Wysoka Proste przypadki, znana struktura
Dynamiczny Tak W czasie działania Wysoka (dla interfejsów) Średnia Wspólna logika dla interfejsów, AOP
CGLIB Nie W czasie działania Wysoka (dla klas) Wysoka AOP, proxy dla klas bez interfejsów