Una explicación completa del proxy estático y el proxy dinámico de Java

1. El papel del modelo proxy

El modo proxy en Java es un patrón de diseño común. El modo proxy puede mejorar la función de la clase sin cambiar el código original. El modo proxy incluye proxy estático y proxy dinámico. El mecanismo subyacente de AOP es el proxy dinámico.

El patrón proxy es un patrón de diseño relativamente bien entendido. En pocas palabras,  usamos objetos proxy para reemplazar el acceso a objetos reales, de modo que podamos proporcionar operaciones funcionales adicionales y ampliar las funciones del objeto de destino sin modificar el objeto de destino original.

A continuación se dará una explicación completa de los dos modos de proxy.

2. Proxy estático

El proxy estático es el código que ha determinado la clase de proxy durante la compilación, y tanto la clase de proxy como la clase de proxy implementan la misma interfaz o heredan de la misma clase principal. La ventaja del proxy estático es que es simple de escribir, fácil de entender y mantener. Sin embargo, si es necesario utilizar proxy para varias clases, la cantidad de clases de proxy aumentará y el código de la clase de proxy deberá mantenerse manualmente cuando aumenten los métodos de la clase de proxy y la clase de proxy.

Aquí hay un ejemplo de proxy estático simple:

public interface Subject {
    void request();
}

public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject:request()");
    }
}

public class ProxySubject implements Subject {
    private RealSubject realSubject;

    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        System.out.println("ProxySubject:before request()");
        realSubject.request();
        System.out.println("ProxySubject:after request()");
    }
}

public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        proxySubject.request();
    }
}

 En el ejemplo anterior, RealSubjectla clase de proxy es ProxySubjectla clase de proxy, y la clase de proxy implementa Subjectla interfaz y contiene una instancia de la clase de proxy RealSubject. En el método de la clase de proxy request(), se llama al método de la clase de proxy request()y se agrega su propia lógica de procesamiento antes y después.

3. Agente dinámico

El proxy dinámico es para generar dinámicamente el código de la clase de proxy en tiempo de ejecución y no necesita conocer el código de la clase de proxy de antemano. Hay dos formas principales de proxy dinámico en Java, una es un proxy dinámico basado en interfaz y la otra es un proxy dinámico basado en clases.

Para realizar un proxy dinámico, ¿qué problemas deben resolverse?

Pregunta 1: Cómo crear dinámicamente una clase de proxy y sus objetos en función de la clase de proxy cargada en la memoria

Pregunta 2: al llamar a un método a través del objeto de la clase de proxy, cómo llamar dinámicamente al método del mismo nombre en la clase de proxy

Proxy dinámico basado en interfaz

Proxy dinámico basado en interfaz significa que la clase de proxy y la clase de proxy implementan la misma interfaz, y la clase de proxy se genera dinámicamente en tiempo de ejecución, sin escribir manualmente el código de la clase de proxy.

En el mecanismo de proxy dinámico de Java, InvocationHandlerlas interfaces y Proxylas clases son el núcleo.

ProxyEl método más utilizado en la clase es: newProxyInstance(), que se utiliza principalmente para generar un objeto proxy.

public static Object newProxyInstance(ClassLoader loader,
                                       Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
{
      ......
}

Este método tiene un total de 3 parámetros:

  1. cargador  : cargador de clases, utilizado para cargar objetos proxy.
  2. interfaces  : algunas interfaces implementadas por la clase proxy;
  3. h  : el objeto que implementa  InvocationHandler la interfaz;

 Para implementar un proxy dinámico, también debe implementar InvocationHandlerpara personalizar la lógica de procesamiento. Cuando nuestro objeto de proxy dinámico llama a un método, la llamada de este método se reenviará al método que implementa la InvocationHandlerclase de interfaz invokea llamar.

public interface InvocationHandler {

    /**
     * 当你使用代理对象调用方法的时候实际会调用到这个方法
     */
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

invoke()El método tiene los siguientes tres parámetros:

  1. proxy : clase de proxy generada dinámicamente
  2. método : corresponde al método llamado por el objeto de clase proxy
  3. args : los parámetros del método actual método

Es decir: cuando el objeto proxy que creaste a través de Proxyla clase llama al método, en realidad llamará al método de la clase que implementa la interfaz . newProxyInstance()InvocationHandlerinvoke()Puede invoke()personalizar la lógica de procesamiento en el método, como qué hacer antes y después de ejecutar el método.

Aquí hay un ejemplo de un proxy dinámico basado en interfaz:

public interface Subject {
    void request();
}
// 被代理类
public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject:request()");
    }
}
// 解决问题二
public class DynamicProxySubject implements InvocationHandler {
    private Object realSubject;

    public DynamicProxySubject(Object realSubject) {
        this.realSubject = realSubject;
    }
    //当我们通过代理类的对象,调用方法request时,就会自动的调用如下的方法: invoke()
    //将被代理类要执行的方法的功能就言明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //method: 即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
        //realSubject: 被代理类的对象
        System.out.println("DynamicProxySubject:before " + method.getName() + "()");
        Object result = method.invoke(realSubject, args);
        System.out.println("DynamicProxySubject:after " + method.getName() + "()");
        //上述方法的返回值就作为当前类中的invoke()的返回值。
        return result;
    }
}

public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        DynamicProxySubject dynamicProxySubject = new DynamicProxySubject(realSubject);
        //调用此方法,返回一个代理类的对象。解决问题一
        Subject proxySubject = (Subject)Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),         
        realSubject.getClass().getInterfaces(), dynamicProxySubject);
        proxySubject.request();
    }
}

En el ejemplo anterior, `RealSubject` es la clase de proxy, `DynamicProxySubject` es la clase de proxy, la clase de proxy implementa la interfaz `InvocationHandler` y llama al método correspondiente de la clase de proxy en el método `invoke()` del clase de proxy, y agregue su propia lógica de procesamiento antes y después. En el código del cliente, una instancia de la clase de proxy se genera dinámicamente llamando al método `Proxy.newProxyInstance()`.

Proxy dinámico basado en clases

Proxy dinámico basado en clases significa que tanto la clase de proxy como la clase de proxy son clases, y la clase de proxy se genera dinámicamente en tiempo de ejecución, sin escribir manualmente el código de la clase de proxy. El proxy dinámico basado en clases en Java se realiza principalmente a través del marco de generación de código de bytes, y los marcos de generación de código de bytes más utilizados incluyen CGLIB y ASM. Aquí hay un ejemplo de un proxy dinámico basado en clases (implementado usando CGLIB):

public class RealSubject {
    public void request() {
        System.out.println("RealSubject:request()");
    }
}

public class DynamicProxySubject implements MethodInterceptor {
    private Object realSubject;

    public DynamicProxySubject(Object realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("DynamicProxySubject:before " + method.getName() + "()");
        Object result = proxy.invoke(realSubject, args);
        System.out.println("DynamicProxySubject:after " + method.getName() + "()");
        return result;
    }
}

public class Client {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealSubject.class);
        enhancer.setCallback(new DynamicProxySubject(new RealSubject()));
        RealSubject proxySubject = (RealSubject) enhancer.create();
        proxySubject.request();
    }
}

En el ejemplo anterior, RealSubjectes la clase de proxy y DynamicProxySubjectla clase de proxy.La clase de proxy implementa la interfaz y llama al método correspondiente de la clase de proxy en el método de la MethodInterceptorclase de proxy , y agrega su propia lógica de procesamiento antes y después. intercept()En el código del cliente, Enhancerse genera una instancia de la clase proxy llamando a la clase proporcionada por CGLIB.

Cuatro Resumen

El proxy estático y el proxy dinámico son implementaciones específicas del patrón de proxy, y ambos pueden mejorar la funcionalidad de una clase, pero de diferentes maneras. El código de la clase de proxy se ha determinado durante la compilación del proxy estático, que es adecuado para la representación de un pequeño número de clases; el código de la clase de proxy es generado dinámicamente por el proxy dinámico en tiempo de ejecución, que es adecuado para la representación de un gran cantidad de objetos o no está seguro de qué clase representar.

El agente estático en Java necesita escribir manualmente el código de la clase de agente, que no es lo suficientemente flexible, pero la eficiencia es alta; el agente dinámico no necesita escribir manualmente el código de la clase de agente, que es más flexible, pero la eficiencia es baja.

Tanto los proxies estáticos como los proxies dinámicos en Java son proxies basados ​​en interfaz, por lo que la clase proxies debe implementar la interfaz.

Los proxies dinámicos se implementan en Java a través del mecanismo de reflexión, lo que generará cierta sobrecarga de rendimiento. Además, debido a que el proxy dinámico es una clase de proxy generada dinámicamente en tiempo de ejecución, no es fácil de depurar.

En aplicaciones prácticas, se puede seleccionar proxy estático o proxy dinámico de acuerdo con la situación específica, como el número de clases que necesitan ser proxy, la estructura de la clase proxy, la complejidad de la clase proxy, el ciclo de vida del proxy la clase y otros factores pueden afectar la elección.

Supongo que te gusta

Origin blog.csdn.net/weixin_44863237/article/details/130426299
Recomendado
Clasificación