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:
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
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:
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); } }
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:
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 ; } }
Finalmente, echemos un vistazo a nuestra clase de Cliente:
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" ); } }
Echemos un vistazo a la salida de la consola primero:
$ 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
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:
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 ; }
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.