La clave para implementar proxy dinámico en Java son estas dos cosas: proxy e invocationHandler. Comencemos con el método de Invoke en la interfaz InvocationHandler y expliquemos brevemente cómo Java implementa proxy dinámico.
Primero, la forma completa del método de Invoke es la siguiente:
Public Object Invoke (Proxy de objeto, método Método, objeto [] args) lanza lando {método.invoke (obj, args); return null;}Primero, supongamos que el método es el método llamado, es decir, el método que debe ejecutarse; Args es el parámetro del método; Proxy, ¿qué es este parámetro? La implementación anterior del método Invoke () es una forma relativamente estándar. Vemos que no se usan parámetros proxy aquí. Consulte la descripción del proxy en la documentación JDK, de la siguiente manera:
Una invocación del método en una instancia de proxy a través de una de sus interfaces proxy se enviará al método de invocación del controlador de invocación de la instancia, que pasa la instancia de proxy, un java.lang.reflect.method Object identificando el método que se invocó y una matriz de objeto de tipo que contiene los argumentos.
De esto podemos saber que la suposición anterior es correcta, y también sabemos que el parámetro proxy es una instancia de la clase proxy.
Para conveniencia de explicación, aquí hay un ejemplo simple para implementar proxy dinámico.
// Rol de abstracto (proxy dinámico solo puede interfaz de proxy) sujeto de interfaz pública {Public void request (); } // rol real: implementó el método request () de sujeto clase pública realSubject implementa sujeto {public void request () {System.out.println ("De Real Sujem"); }} // Implementar InvocationHandler Public Class DynamicSubject implementa InvocationHandler {objeto privado obj; // Este es el beneficio del proxy dinámico. El objeto encapsulado es de tipo de objeto y acepta objetos de cualquier tipo public DynamicSubject () {} public DynamicSubject (object obj) {this.obj = obj; } // Este método no es lo que mostramos para llamar a Public Object Invoke (Proxy de Object, Método, Método, Object [] args) lanza Throwable {System.out.println ("Antes de llamar" + método); método.invoke (obj, args); System.out.println ("después de llamar" + método); regresar nulo; }} // Cliente: Genere una instancia de proxy y llame al método de request () Public Class Client {public static void main (string [] args) lanza lanzable {// TODO Auto Generado Método STUB SUMPT rs = new RealSubject (); // Especifique la clase Proxy InvocationHandler ds = new DynamicSubject (RS); Clase <?> Cls = rs.getClass (); // La siguiente es una generación única de sujeto proxy sujeto = (sujeto) proxy.newproxyInstance (cls.getClassLoader (), cls.getInterfaces (), ds); // Aquí puede probar que el sujeto es una instancia de proxy ejecutando los resultados. Esta instancia implementa la interfaz de sujeto System.out.println (instancia de sujeto de proxy); // Aquí puede ver que la clase de clase del sujeto es $ proxy0. Esta clase $ proxy0 hereda el proxy e implementa la interfaz de sujeto System.out.println ("La clase de clase de sujeto es:"+tema.getClass (). ToString ()); System.out.print ("Las propiedades en el sujeto son:"); Campo [] campo = sujeto.getClass (). GetDeclaredFields (); for (campo f: campo) {system.out.print (f.getName ()+","); } Los métodos en System.out.print ("/n"+"sujeto son:"); Método [] método = saters.getClass (). GetDeclaredMethods (); para (método m: método) {system.out.print (m.getName ()+","); } La clase principal de System.out.println ("/n"+"El sujeto es:"+Sujeto.getClass (). GetsuperClass ()); System.out.print ("/n"+"El tema implementa la interfaz:"); Class <?> [] Interfaces = seno.getClass (). GetInterfaces (); para (clase <?> i: interfaces) {system.out.print (i.getName ()+","); } System.out.println ("/n/n"+"El resultado de ejecución es:"); Sujeto.Request (); }} El resultado de la operación es el siguiente: el nombre del paquete se omite aquí, *** en su lugar
verdadero
La clase de clase de asignatura es: Clase $ proxy0
Las propiedades en el sujeto son: M1, M3, M0, M2,
Los métodos en sujeto son: solicitud, hashcode, iguales, tostring,
La clase matriz de asignatura es: clase java.lang.reflect.proxy
La interfaz implementada por sujeto es: cn.edu.ustc.dynamicproxy.subject,
El resultado de la operación es:
Antes de llamar a Public Abstract Void ***. SUMPLAT.REQUEST ()
De sujeto real.
Después de llamar a Public Abstract void ***. SUMPLAT.REQUEST ()
PD: La información sobre este resultado es muy importante, al menos para mí. Porque la causa raíz de mi mareo en el proxy dinámico es que malinterpreté el tema anterior. Una vez estuve confundido acerca de cómo la última solicitud de llamada () estaba conectada para invocar (), y cómo Invoke sabía que existe la solicitud. De hecho, el verdadero y la clase $ proxy0 anterior pueden resolver muchas preguntas y, junto con el código fuente de $ proxy0, que se mencionará a continuación, puede resolver completamente las dudas del proxy dinámico.
En el código y los resultados anteriores, podemos ver que no llamamos al método Invoke () como se muestra, pero este método se ejecutó. Analicemos todo el proceso a continuación:
A juzgar por el código en el cliente, puede usar el método NewProxyInstance como avance. Primero veamos el código fuente del método NewProxyInstance en la clase proxy:
Interfaces públicas de objeto estático newProxyInstance (ClassLoader Loader, class <?> [] Interfaces, InvocationHandler H) arroja ilegalArgumentException {if (h == null) {lanzar nueva nullPointerException (); } / * * Busque o genere la clase proxy diseñada. */ Class cl = getProxyClass (cargador, interfaces); / * * Invoca su constructor con el controlador de invocación diseñado. * / try { / * * El código fuente de proxy tiene la siguiente definición: * clase estática final privada [] constructorParams = {invocationHandler.class}; * Consiad es el método del constructor con los parámetros formales del tipo InvocationHandler*/ Constructor Cons = cl.getConstructor (ConstructorParams); return (object) cons.NewinStance (nuevo objeto [] {h}); } catch (nosuchmethodexception e) {throw new GonalError (e.ToString ()); } Catch (ilegalAccessException e) {Throw New GonalErsor (e.ToString ()); } Catch (InstanciationException e) {Throw New GonalErsor (e.ToString ()); } catch (InvocationTargetException e) {Throw New GonalError (e.ToString ()); }} Proxy.newproxyInstance (ClassLoader Loader, Class <?> [] Interfaces, InvocationHandler H) hace las siguientes cosas.
(1) Llame al método getProxyClass (cargador, interfaces) basado en el cargador e interfaces de parámetros, cree la clase proxy $ proxy0. $ Proxy0 clase, implementa las interfaces de interfaces e hereda la clase proxy.
(2) Instanciar $ proxy0 y pasar dinamicsubject en el constructor, luego $ proxy0 llama al constructor del proxy de clase principal y asigna un valor a h, como sigue:
clase proxy {invocationHandler h = null; Proxy protegido (InvocationHandler h) {this.h = h; } ...}Echemos un vistazo al código fuente que hereda el $ proxy0 de Proxy:
Public Final Clase $ proxy0 extiende Proxy Implements Sujeto {Método estático privado M1; Método estático privado M0; Método estático privado M3; Método estático privado M2; static {try {m1 = class.forname ("java.lang.object"). getMethod ("igual", nueva clase [] {class.forname ("java.lang.object")}); m0 = class.forname ("java.lang.object"). getMethod ("hashcode", nueva clase [0]); m3 = class.forname ("***. RealSubject"). getMethod ("solicitud", nueva clase [0]); m2 = class.forname ("java.lang.object"). getMethod ("toString", nueva clase [0]); } Catch (nosuchmethodexception nosuchmethodexception) {tire nuevo nosuchmethoderror (nosuchmethodexception.getMessage ()); } Catch (ClassNotFoundException ClassNotFoundException) {tire neoClassDefFoundError (classNotFoundException.getMessage ()); }} // público estático $ proxy0 (InvocationHandler InvocationHandler) {super (InvocationHandler); } @Override public Final Boolean iguales (object obj) {try {return ((boolean) super.h.invoke (this, m1, nuevo objeto [] {obj})) .BooleanValue (); } Catch (Throwable Throwable) {Throw New Und -DeClaredThrowableException (Throwable); }} @Override public final int hashcode () {try {return ((integer) super.h.invoke (this, m0, null)). IntValue (); } Catch (Throwable Throwable) {Throw New Und -DeClaredThrowableException (Throwable); }} Public Final Void requit () {try {super.h.invoke (this, m3, null); devolver; } catch (Error e) {} Catch (showable showleable) {lanzar new Und -DeClaredThrowableException (Throwable); }} @Override public Final String ToString () {try {return (string) super.h.invoke (this, m2, null); } Catch (Throwable Throwable) {Throw New Und -DeClaredThrowableException (Throwable); }}}Luego coloque la instancia de $ proxy0 resultante en un sujeto y asigne la referencia al sujeto. Cuando se ejecuta el método Sujeto.Request (), se llama al método request () en la clase $ proxy0, y se llama al método invoke () de h en el proxy de la clase principal. Es decir, invocationHandler.invoke ().
PS: 1. Una cosa a tener en cuenta es que el método GetProxyClass en la clase Proxy devuelve la clase de la clase de proxy. ¡La razón de esto es que cometí un error de bajo nivel al principio, pensando que el regreso es "clase de clase de la clase proxy"-! Se recomienda echar un vistazo al código fuente de GetProxyClass, que es muy largo =. =
2. Del código fuente de $ proxy0, se puede ver que la clase dinámica de proxy no solo proxera los métodos en la interfaz definida de pantalla, sino también los tres métodos heredados de igual (), hashcode () y toString () en el objeto de clase raíz de Java, y solo estos tres métodos.
P: Hasta ahora, todavía hay una pregunta. El primer parámetro en el método de Invoke es una instancia de proxy (para ser precisa, la instancia de $ proxy0 finalmente se usa), pero ¿cuál es el uso? O, ¿cómo aparece la función en el programa?
R: Desde mi nivel actual, este parámetro proxy no tiene ningún efecto. En todo el mecanismo de proxy dinámico, no se utiliza el parámetro proxy del método Invoke en InvocationHandler. El parámetro pasado es en realidad una instancia de la clase proxy. Creo que podría ser permitir que los programadores usen la reflexión en el método de Invoke para obtener información sobre la clase proxy.
Resumir
Lo anterior es todo el contenido de este artículo sobre el método Invoke () en InvocationHandler. Espero que sea útil para todos. Los amigos interesados pueden continuar referiéndose a este sitio:
Explicación detallada del proxy static spring y el código de proxy dinámico
Spring Framework Dependency Inyection Método Ejemplo
Implementación de programación de Java del ejemplo de inicio de sesión simple de SpringMVC
Si hay alguna deficiencia, deje un mensaje para señalarlo.