@Transactional @async y otras anotaciones no funcionan
Antes, muchas personas han encontrado algunas situaciones en las que la anotación no funciona cuando se usa @Transactional, @async y otras anotaciones en primavera.
¿Por qué ocurren estas situaciones? Debido a que las funciones de estas anotaciones son realmente implementadas por Spring AOP, y sus principios de implementación se implementan a través del proxy.
JDK proxy dinámico
Comprendamos los principios básicos del proxy dinámico JDK con un ejemplo simple:
// Interfaz de clase de destino Interface Public Interface JDKProxyTestService {void run ();} // class de clase de destino public class jdkproxytestserviceImpl implementa jdkproxytestservice {public void run () {System.out.println ("do algo ..."); }} // clase proxy public class testjdkproxy implementa invocationHandler {private object TargetObject; // Objeto objetivo de proxy // Construye el objeto Proxy Public Object newProxy (objeto TargetObject) {this.tarGetObject = TargetObject; return proxy.newproxyInstance (TargetObject.getClass (). GetClassLoader (), TargetObject.getClass (). GetInterfaces (), esto); } // Use la reflexión para realizar una mejora lógica en la lógica original del objeto de objeto de objeto (proxy de objeto, método método, objeto [] args) lanza lando {// simular inicio de transacción asumeBeBeGinTransaction (); // Objeto lógico de ejecución original ret = Method.Invoke (TargetObject, Args); // Sumisión de transacción simulada AssumeComMitTransaction (); regreso de regreso; } private void asumeBeBeGinTransaction () {System.out.println ("Inicio de transacción simulada ..."); } private void asumeCommitTransaction () {System.out.println ("Mock Transaction Envision ..."); }} // Test Public Class Test {public static void main (string [] args) {testjdkproxy jdkproxy = new testjdkproxy (); JDKPROXYTESTSERVICE proxy = (jdkproxytestservice) jdkproxy.newproxy (nuevo jdkproxytestserviceImpl ()); proxy.run (); }}El ejemplo anterior debería poder explicar claramente el principio del proxy dinámico JDK. Utiliza el mecanismo de reflexión para generar una clase anónima que implementa la interfaz proxy y llama a InvokeHandler para manejarlo antes de llamar al método específico. Cuando llamamos a un método a través de un objeto de clase proxy, primero llamaremos su método de invocación y luego llamaremos al método original. De esta manera, podemos agregar una lógica de procesamiento de manera uniforme antes y después de la lógica del método original.
Spring también tiene un método de proxy dinámico que es el proxy dinámico CGLIB. Carga el archivo de clase de la clase de objetos proxy y lo procesa modificando su bytecode para generar subclases. Aunque los métodos de manejo son diferentes, las ideas de la agencia son consistentes.
Si el objeto de destino que está proxyed implementa una interfaz, Spring usará el proxy dinámico JDK de forma predeterminada. Todas las interfaces implementadas por este tipo de objetivo serán proxyes. Si el objeto de destino no implementa ninguna interfaz, se crea un proxy CGLIB.
Falla y resolución de la anotación de la AOP de primavera
Basado en el análisis anterior del principio de proxy dinámico, veamos los siguientes dos problemas comunes:
En la misma clase, el método A llama método B (anotado en el método B), y la anotación no es válida.
Para todas las anotaciones de AOP de primavera, si Spring encuentra tales anotaciones al escanear los frijoles, construirá dinámicamente un objeto proxy.
Esta anotación es válida si desea llamar directamente al método A con anotación a través de un objeto de la Clase X. Porque en este momento, Spring determinará que hay una anotación AOP en el método que está a punto de llamar, y luego usará el objeto proxy de la Clase X para llamar Método A.
Pero suponga que el método A en la clase X llamará al método B con anotación, y aún desea llamar al Método A a través del objeto de la Clase X, entonces la anotación en el Método B no es válida. Debido a que Spring determina que la A que llama no tiene anotación, el objeto original todavía se usa en lugar del objeto proxy. Cuando A llama a B siguiente, la anotación del método B en el objeto original, por supuesto, no es válida.
Solución:
La forma más fácil es, por supuesto, hacer que los métodos A y B no tengan dependencias y pueden llamar directamente el método B a través del objeto de la clase X.
Pero muchas veces, nuestra lógica puede no estar bien escrita de esta manera, por lo que hay otro método: encontrar una manera de obtener manualmente el objeto proxy.
La clase AOPContext tiene un método CurrentProxy () que puede obtener directamente el objeto proxy de la clase actual. Entonces el ejemplo anterior se puede resolver así:
// Método de llamada B Método interno A // 1. Llame B directamente, la anotación no es válida. B () // 2. Obtenga el objeto de clase proxy y llame a B. ((x) aopContext.CurrentProxy ()). B ()
El objeto @aUtowired es nulo en el método de anotación AOP
En uso anterior, en el método de anotación, cuando se usa otros objetos inyectados, se descubrió que el objeto no se inyectó, y era nulo.
Finalmente, se descubrió que la razón de esto era porque el método era privado. Debido a que Spring usa proxy dinámico JDK o proxy dinámico CGLIB, uno es una clase que implementa la interfaz y la otra se implementa a través de subclases. Ni la interfaz ni la clase principal, el método privado puede estar presente, de lo contrario ni la subclase ni la clase de implementación pueden ser anuladas.
Si el método es privado, entonces este método no se puede encontrar en el proceso de proxy, causando problemas en la creación de objetos proxy y haciendo que algunos objetos no se inyecten.
Entonces, si el método necesita usar anotaciones AOP, configúrelo en un método no privado.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.