Java: mecanismo de agente dinámico detallado

Al aprender Spring, sabemos que Spring tiene dos ideas principales, una es IoC y la otra es AOP. Para IoC, la inyección de dependencia no necesita decir mucho, y para el AOP central de Spring, no solo debemos saber cómo pasar AOP para cumplir con nuestras funciones, necesitamos aprender más sobre el principio subyacente, y el principio de AOP es el mecanismo de proxy dinámico de Java, por lo que este ensayo es una revisión del mecanismo dinámico de Java.

En el mecanismo de proxy dinámico de java, hay dos clases o interfaces importantes, una es InvocationHandler (Interface), la otra es Proxy (Class), esta clase e interfaz son necesarias para lograr nuestro proxy dinámico. Primero, echemos un vistazo a cómo la documentación de ayuda de la API de Java describe estas dos clases:

InvocationHandler:

InvocationHandler es la interfaz implementada por el controlador de invocación de una instancia de proxy. 

Cada instancia de proxy tiene un controlador de invocación asociado. Cuando se invoca un método en una instancia de proxy, la invocación del método se codifica y se envía al método de invocación de su manejador de invocación.

Cada clase de proxy dinámico debe implementar la interfaz InvocationHandler, y cada instancia de la clase de proxy está asociada con un controlador. Cuando llamamos a un método a través del objeto proxy, la llamada al método se reenviará a la interfaz de InvocationHandler Para invocar el método de invocación. Echemos un vistazo a InvocationHandler sólo un método de esta interfaz de invocación de métodos:

La invocación de objeto (proxy de objeto, método de método, argumentos de Object []) arroja Throwable

Vemos que este método acepta un total de tres parámetros, entonces, ¿qué representan estos tres parámetros?

Objeto de la Invoke (objeto proxy, Método Método ,, Object [] args) throws Throwable Proxy :  se refiere al objeto real que son agentes de Método, :  se refiere a un método objeto queremos llamar a un método de un objeto real de args :  se refiere a la ¿Se acepta el parámetro cuando se llama a un método en un objeto real?



Si no lo comprende, le explicaremos estos parámetros con mayor profundidad a través de un ejemplo.

A continuación, echemos un vistazo a la clase Proxy:

Proxy proporciona métodos estáticos para crear clases e instancias de proxy dinámico, y también es la superclase de todas las clases de proxy dinámico creadas por esos métodos.

La función de la clase Proxy es crear dinámicamente una clase de objeto proxy, que proporciona muchos métodos, pero lo que más utilizamos es el método newProxyInstance :

pública  estática objeto newProxyInstance (cargador de clases de cargador, Clase <?> [] interfaces h InvocationHandler)   lanza IllegalArgumentException
Devuelve una instancia de una clase de  proxy para las interfaces especificadas que envía invocaciones de métodos al manejador de invocación especificado.

La función de este método es obtener un objeto proxy dinámico, que recibe tres parámetros, echemos un vistazo al significado de estos tres parámetros:

Código de copia
El  objeto estático público newProxyInstance (cargador de ClassLoader, interfaces de clase <?> [], InvocationHandler h) lanza el cargador IllegalArgumentException :  un objeto de ClassLoader, que define qué objeto de ClassLoader cargará las interfaces de objetos proxy generados :  una matriz de objetos de interfaz Lo que quiero es proporcionar un conjunto de interfaces para los objetos que necesito para proxy, si le proporciono un conjunto de interfaces, entonces el objeto proxy afirma implementar la interfaz (polimorfismo), para que pueda llamar a este conjunto de interfaces El método es h :  un objeto InvocationHandler, que indica a qué objeto InvocationHandler se asociará cuando mi objeto proxy dinámico llame al método





Código de copia

Bueno, después de presentar estas dos interfaces (clases), echemos un vistazo a un ejemplo para ver cómo se ve nuestro modelo de proxy dinámico:

Primero definimos una interfaz de tipo Asunto y declaramos dos métodos para ello:

 interfaz pública Asunto 
{ 
    public  void rent (); 
    
    público  vacío hola (String str); 
}

Luego, defina una clase para implementar esta interfaz, esta clase es nuestro objeto real, la clase RealSubject:

Código de copia
public  class RealSubject implementa Subject 
{ 
    @Override 
    public  void rent () 
    { 
        System.out.println ( "Quiero alquilar mi casa" ); 
    } 
    
    @Override 
    public  void hello (String str) 
    { 
        System.out.println ( "hello:" + str); 
    } 
}
Código de copia

A continuación, tenemos que definir una clase de proxy dinámico. Como se mencionó anteriormente, cada clase de proxy dinámico debe implementar la interfaz InvocationHandler, por lo que nuestra clase de proxy dinámico no es una excepción:

Código de copia
La  clase pública DynamicProxy implementa InvocationHandler 
{ 
    //  Este es el objeto real que queremos proxy 
    sujeto privado Objeto; 
    
    //     Método de construcción, asigne el valor inicial al objeto real que queremos proxy 
    público DynamicProxy (Objeto objeto) 
    { 
        this .subject = subject; 
    } 
    
    @ Invalidar 
    la invocación pública de objetos (objeto Object, método Method, Object [] args)
             arroja Throwable 
    { 
        //   Podemos agregar algunas de nuestras propias operaciones antes de proxigar objetos reales 
        System.out.println ("before rent house" ); 
        
        System.out. println ( "Método:" + método); 
        
        //    Cuando el objeto proxy llama al método del objeto real, saltará automáticamente al método de invocación del objeto controlador asociado con el objeto proxy para llamar a 
        method.invoke (subject, args); 
        
        //   También podemos agregar algunos después del objeto real proxy Operación propia 
        System.out.println ("después de la casa de renta" ); 
        
        retorno  nulo ; 
    } 

}
Código de copia

Finalmente, echemos un vistazo a nuestra clase de Cliente:

Código de copia
public  class Client 
{ 
    public  static  void main (String [] args) 
    { 
        //     El objeto real que queremos proxy 
        Asunto realSubject = new RealSubject (); 

        //     Qué objeto real queremos proxy, pasar el objeto y finalmente pasar El objeto real para llamar a su método 
        InvocationHandler handler = new DynamicProxy (realSubject); 

        / * 
         * El método newProxyInstance del proxy para crear nuestro objeto proxy, echemos un vistazo a sus tres parámetros 
         * El primer parámetro handler.getClass () .getClassLoader (), usamos el objeto ClassLoader de la clase de controlador para cargar nuestro objeto proxy 
         * realSubject.getClass el segundo parámetro (). getInterfaces (), estamos aquí para proporcionar una interfaz para el objeto proxy es un objeto real para implementar una interfaz , Indicando que quiero proxy del objeto real, para poder llamar a los métodos en este conjunto de interfaces
         * El tercer controlador de parámetros, asociamos este objeto proxy con el objeto InvocationHandler anterior 
          =* / 
        Asunto Asunto(Asunto) Proxy.newProxyInstance (handler.getClass (). GetClassLoader (), realSubject 
                .getClass (). GetInterfaces (), handler); 
        
        System.out.println (subject.getClass (). GetName ()); 
        subject.rent (); 
        subject.hello ( "mundo" ); 
    } 
}
Código de copia

Echemos un vistazo a la salida de la consola primero:

Código de copia
$ Proxy0
 
antes de la casa de renta 
Método: resumen público  nulo  com.xiaoluo.dynamicproxy.Subject.rent () 
Quiero alquilar mi casa 
después de la casa de 

renta antes de la casa de renta 
Método: público  abstracto  nulo com.xiaoluo.dynamicproxy.Subject.hello (java. lang.String) 
hola: mundo 
después de la casa de renta
Código de copia

Primero echemos un vistazo a la cosa $ Proxy0. Vemos que esto está impreso por System.out.println (subject.getClass (). GetName ()); Es por eso que devolvimos este objeto proxy ¿El nombre de la clase es así?

Asunto subject = (Asunto) Proxy.newProxyInstance (handler.getClass (). GetClassLoader (), realSubject 
                .getClass (). GetInterfaces (), handler);

Tal vez pensé que el objeto proxy devuelto sería un objeto de tipo Asunto, o un objeto de InvocationHandler, pero el resultado no es. Primero, expliquemos por qué podemos convertirlo aquí en un objeto de tipo Asunto. La razón es que en el segundo parámetro del método newProxyInstance, proporcionamos un conjunto de interfaces para el objeto proxy, luego mi objeto proxy implementará este conjunto de interfaces, en este momento, por supuesto, podemos convertir el objeto proxy en conversión de tipo obligatoria Para cualquiera de este grupo de interfaces, dado que la interfaz aquí es del tipo Asunto, se puede convertir al tipo Asunto .

Al mismo tiempo, debemos recordar que el objeto proxy creado por Proxy.newProxyInstance es un objeto generado dinámicamente cuando se está ejecutando jvm. No es nuestro tipo InvocationHandler ni el tipo de grupo de interfaz que definimos, pero se está ejecutando. Un objeto generado dinámicamente, y el método de denominación está en esta forma, comenzando con $, el proxy está en, y el último número indica la etiqueta del objeto .

Luego echamos un vistazo a estas dos oraciones 

subject.rent ();
subject.hello ("mundo");

Este es el método del tipo de interfaz implementado a través del objeto proxy. En este momento, el programa saltará al método invocar en el controlador asociado con el objeto proxy para ejecutar, y nuestro objeto controlador acepta un RealSubject. El parámetro type indica que es este objeto real el que quiero proxy, por lo que en este momento, se llamará al método de invocación en el controlador para ejecutar:

Código de copia
invocación de objeto público (objeto de objeto, método de método, argumentos de Object [])
             arroja Throwable 
    { 
        //   Podemos agregar algunas de nuestras propias operaciones antes de representar el objeto real 
        System.out.println ("before rent house" ); 
        
        System.out.println ( "Método:" + método); 
        
        //     Cuando el objeto proxy llama al método del objeto real, saltará automáticamente al método de invocación del objeto controlador asociado con el objeto proxy para llamar a 
        method.invoke (subject, args); 
        
        / /   Después de representar objetos reales, también podemos agregar algunas de nuestras propias operaciones 
        System.out.println ("after rent house" ); 
        
        return  null ; 
    }
Código de copia

Vemos que cuando se llama al método del objeto real a través del objeto proxy, podemos agregar algunas de nuestras propias operaciones antes y después del método, y vemos que nuestro objeto del método es así:

 resumen  público vacío com.xiaoluo.dynamicproxy.Subject.rent () 

resumen público  vacío com.xiaoluo.dynamicproxy.Subject.hello (java.lang.String) 

Resulta que son dos métodos en nuestra interfaz de Asunto, lo que demuestra que cuando llamo a un método a través de un objeto proxy, en realidad se delega para ser invocado por el método de invocación del objeto controlador con el que está asociado, no por mí mismo. Llamada real, pero llama a través del agente.

Este es nuestro mecanismo proxy dinámico de Java

 

Este ensayo explica en detalle el mecanismo de proxy dinámico en Java. Este punto de conocimiento es muy importante, incluido nuestro Spring AOP que se implementa a través del mecanismo de proxy dinámico, por lo que debemos entender bien el mecanismo de proxy dinámico.


Publicado 7 artículos originales · 69 alabanzas · 200,000+ visitas

Supongo que te gusta

Origin blog.csdn.net/u014320421/article/details/79770743
Recomendado
Clasificación