¿Con qué se implementa Spring Aop?
Primero, se implementa a través de proxies estáticos. La clave del proxy estático es implementar la misma interfaz entre el objeto proxy y el objeto de destino, y el objeto proxy contiene una referencia al objeto de destino.
Hombre * * *Código de interfaz:
1 Interfaz pública Hola {2 /**3? *¿Método empresarial 4? * @param str5? */6 void say hola(String str); 7}
Código de categoría de objeto:
1 La clase pública Hola implementa IHello{2? @ override 3 public void say hola(String str){ 4 system out . println(" hola " 5 ?}6 7 }
Código de agente, le agregamos la función de registro, en el método Ejecuta métodos específicos antes y después del inicio. ¿Es muy similar a AOP?
La clase pública ProxyHello implementa IHello{
IHello privado hola;
proxy público hola(IHello hola){ super(); p>
}
@ Anular public void decir hola(String str){
logger start(); //Agregar método específico hola(str);
logger . end();
}
}
Código de categoría de registro:
1 clase pública Registrador {2 inicio vacío estático público(){ 3 salida del sistema. println(nueva fecha() "saluda inicio..."); 5 6 salida del vacío estático público(){ 7 salida del sistema. new Date() " saludar fin "); 8 ?}9 }
Código de prueba:
1 prueba de clase pública { 2 public static void main(String[]args ){ 3 IHello Hello = new proxy Hello(new Hello()); //Si necesitamos la función de registro, use la clase de proxy 4//IHello Hello = new Hello(); //Si no necesitamos la función de registro, use la clase objetivo 5 hola. diga hola(" mañana ");
6 ?}7 }
De esta manera hemos implementado el AOP más simple, pero habrá un problema: Si tenemos muchas clases como Hello, ¿también tenemos que escribir muchas clases como HelloProxy? De hecho, también es algo muy problemático. Después de jdk1.3, ¿jdk nos proporciona una API? Java.lang.reflect. Clase de controlador de invocación, esta clase nos permite hacer algo dinámicamente cuando la JVM llama a algunos métodos. Implementemos la implementación del proxy dinámico.
La implementación del proxy dinámico implementa principalmente InvocationHandler, inyecta el objeto de destino en el objeto proxy y utiliza el mecanismo de reflexión para ejecutar el método del objeto de destino.
La implementación de la interfaz es la misma que la del proxy estático, el código de la clase de proxy:
1 La clase pública DynaProxyHello implementa InvocationHandler{ 2? 3 Destino del objeto privado // Objeto de destino 4 / ** 5? * ¿Crear una instancia del objeto objetivo mediante la reflexión? * @param objeto 7? *@retorno 8? */ 9 enlace de objeto público(Objeto Objeto){ 10 este.objeto = Objeto; 11 retorno proxy(este.objeto.getclass().getClassLoader(), this.target.getClass().getInterfaces(), esto) ; 12 ? } 13 14 ? @Override15 Llamada de objeto público (proxy de objeto, método de método, parámetro de objeto []) 16 Throwable { 17 Resultado de objeto = null 18 inicio (); objeto Método 20Resultado = método. Llame a (this. target, args) a través del mecanismo de reflexión; 21 ?logger end(); 22 devuelve el resultado 23 ?}24 25 }
Código de categoría de prueba:
1 prueba dyna de clase pública { 2 public static void main(String[]args){ 3 Hola hola =(Hola)nuevo DynaProxyHello(). bind(new Hello());//Si necesitamos la función de registro, use la clase de proxy 4//IHello Hello = new Hello();//Si no necesitamos la función de registro, use la clase de destino 5 hola. saluda(" mañana "); 6 ?}7 }
Después de leer el código anterior, puede haber problemas al compararlo con Spring AOP. La clase de registro solo puede imprimir antes y después del método, pero AOP debe ejecutarse cuando se cumplan las condiciones. Entonces, ¿se pueden desacoplar el objeto DynaPoxyHello y Logger?
Observe la siguiente implementación de código, que desacoplará el objeto DynaPoxyHello y el registrador:
Necesitamos agregar el código de operación de registro (u otro código de operación) antes o después del método. del código objeto proxy). Luego, podemos abstraer una interfaz, que tiene solo dos métodos: uno es un método que se ejecuta antes de que el objeto proxy ejecute el método, al que llamamos inicio, y el segundo es un método que se ejecuta después de que el objeto proxy ejecuta el método. , que pedimos que se ponga fin.
Interfaz del registrador:
1 Interfaz pública ILogger {2 inicio vacío (método de método); 3 final vacío (método de método 4}
Registrar la interfaz; implementación del dispositivo;
1 La clase pública DLogger implementa ILogger{ 2? @Override 3 public void start(Método método){ 4 system . println(new Date() Método. getname() "di hola inicio..."); Método){ 8 sistema. println(nueva fecha() Método. getname() " saludar final " 9 ?}10 }
Clase de proxy dinámico:
1 Clase pública dynaproxyHello 1 implementa el controlador de llamadas { 2 // Llamar al objeto 3 proxy de objeto privado; 4 // Objeto objetivo 5 objetivo privado 6? 7 enlace de objeto público (objeto objetivo, objeto proxy) { 8 this.target = target9 this. proxy = proxy10 return proxy. newproxyinstance(this. target. getclass(). getClassLoader(), this.target.getClass(). getInterfaces(), this 11 ?}12 13 14 ?@Override15 llamada de objeto público (Proxy de objeto); , método método, objeto [] parámetro) 16 Throwable { 17 resultado del objeto = null18 // Instancia del operador refleja 19 clase clazz = this proxy 20 // La reflexión obtiene el método de inicio del método del operador 21 = clazz. . getdeclaredmethod ("inicio", nueva clase [] {method. class }); 22 // Método de inicio de ejecución de reflexión 23 start.invoke (this. proxy, new object [] { this . proxy . getclass ()}); /Ejecutar el método original 25. Call (this. target, argumentos del objeto a procesar); 26 //La reflexión obtiene el método final del operador 27 métodoend = clazz. getdeclaredmethod ("fin", nueva clase [] {método. clase}); 28 // Método final de ejecución de reflexión 29 end.invoke (este. proxy, nuevo objeto [] {método}); 33 }
Código de prueba:
1 clase pública DynaTest1 {2 public static void main(String[]args){ 3 Hola hola = (Hola) nuevo DynaProxyHello1().
bind(new Hello(), new DLogger()); //Si necesitamos la función de registro, use la clase proxy 4 //IHello Hello = new Hello() //Si no necesitamos la función de registro, use el clase de destino 5 hola. decir hola ("mañana"); 6 ?}7 }
A través del ejemplo anterior, podemos encontrar que las funciones de AOP se han realizado básicamente a través de proxy dinámico y tecnología de inicio. Si solo necesitamos imprimir el registro antes de ejecutar el método, no es necesario implementar el método end(), para que podamos controlar el tiempo de impresión. Si desea imprimir registros mediante un método específico, solo necesita agregar un juicio sobre el nombre del método en el método invoke (), y el nombre del método se puede escribir en el archivo xml para que se pueda desacoplar de la configuración. archivo y lograr un marco simple de primavera aop.