@Transactional @async et d'autres annotations ne fonctionnent pas
Avant, de nombreuses personnes ont rencontré certaines situations où l'annotation ne fonctionne pas lors de l'utilisation de @Transactional, @async et d'autres annotations au printemps.
Pourquoi ces situations se produisent-elles? Parce que les fonctions de ces annotations sont réellement implémentées par Spring AOP, et leurs principes de mise en œuvre sont implémentés par procuration.
Proxy dynamique JDK
Comprenons les principes de base du proxy dynamique JDK avec un exemple simple:
// Interface de classe cible interface publique jdkproxytestService {void run ();} // classe cible classe publique jdkproxytestServiceImplt implémente jdkproxytestService {public void run () {system.out.println ("faire quelque chose ..."); }} // Classe de proxy classe publique TestJDKProxy implémente invocationHandler {private Object TargetObject; // Proxy Target Object // Construire l'objet Proxy Object Public Object NewProxy (objet TargetObject) {this.targetObject = TargetObject; return proxy.newproxyinstance (targetObject.getClass (). getClassOader (), targetObject.getClass (). getInterfaces (), this); } // Utilisez la réflexion pour effectuer une amélioration logique sur l'objet public logique d'origine invoquer (proxy d'objet, méthode de la méthode, objet [] args) lance le throwable {// simuler le démarrage de la transaction assumebegintransaction (); // Logic d'exécution d'origine Object Ret = Method.Invoke (TargetObject, Args); // simule la soumission des transactions AssuMemMitTransaction (); retour retour; } private void assumebegintransaction () {System.out.println ("Mock Transaction start ..."); } private void assumeMitTransaction () {System.out.println ("Mock Transaction Soumission ..."); }} // Test de classe publique Test {public static void main (String [] args) {testjdkproxy jdkproxy = new TestJdkProxy (); JdkproxytestService proxy = (jdkproxytestService) jdkproxy.newproxy (new JDKProxyTestServiceImpll ()); proxy.run (); }}L'exemple ci-dessus devrait être en mesure d'expliquer clairement le principe du proxy dynamique JDK. Il utilise le mécanisme de réflexion pour générer une classe anonyme qui implémente l'interface proxy, et appelle InvokeHandler pour le gérer avant d'appeler la méthode spécifique. Lorsque nous appelons une méthode via un objet de classe proxy, nous appellerons d'abord sa méthode invoquée, puis appelons la méthode d'origine. De cette façon, nous pouvons ajouter une logique de traitement uniformément avant et après la logique de méthode d'origine.
Spring a également une méthode de proxy dynamique qui est le proxy dynamique CGLIB. Il charge le fichier de classe de la classe d'objets proxy et le traite en modifiant son bytecode pour générer des sous-classes. Bien que les méthodes de manutention soient différentes, les idées de l'agence sont cohérentes.
Si l'objet cible étant proxy implémente une interface, Spring utilisera JDK Dynamic Proxy par défaut. Toutes les interfaces implémentées par ce type de cible seront proxyées. Si l'objet cible n'implémente aucune interface, un proxy CGLIB est créé.
Spring AOP Annotation défaillance et résolution
Sur la base de l'analyse ci-dessus du principe de proxy dynamique, examinons les deux problèmes communs suivants:
Dans la même classe, la méthode A appelle la méthode B (annotée sur la méthode B), et l'annotation n'est pas valide.
Pour toutes les annotations Spring AOP, si Spring trouve de telles annotations lors du balayage, il construire dynamiquement un objet proxy.
Cette annotation est valide si vous souhaitez appeler directement la méthode avec une annotation via un objet de classe X. Parce qu'à ce moment, Spring déterminera qu'il y a une annotation AOP sur la méthode que vous êtes sur le point d'appeler, puis il utilisera l'objet proxy de la classe X pour appeler la méthode A.
Mais supposons que la méthode A dans la classe X appellera la méthode B avec l'annotation, et que vous souhaitez toujours appeler la méthode A traversant l'objet de classe X, alors l'annotation sur la méthode B n'est pas valide. Parce que Spring détermine que l'appel A A n'a pas d'annotation, l'objet d'origine est toujours utilisé plutôt que l'objet proxy. Lorsqu'un appelle B ensuite, l'annotation de la méthode B dans l'objet d'origine est bien sûr invalide.
Solution:
Le moyen le plus simple est bien sûr de faire des méthodes A et B sans dépendances et peut appeler directement la méthode B à l'objet de la classe X.
Mais plusieurs fois, notre logique n'est peut-être pas bien écrite de cette manière, il existe donc une autre méthode: trouver un moyen d'obtenir manuellement l'objet proxy.
La classe AOPContext a une méthode CurrentProxy () qui peut obtenir directement l'objet proxy de la classe actuelle. Ensuite, l'exemple ci-dessus peut être résolu comme ceci:
// Appel Méthode B INTERNE MÉTHODE A // 1. Appelez B directement, l'annotation n'est pas valide. B () // 2. Obtenez l'objet de classe proxy et appelez B. ((x) aopContext.currentProxy ()). B ()
L'objet @Autowired est nul dans la méthode d'annotation AOP
Dans une utilisation précédente, dans la méthode d'annotation, lors de l'utilisation d'autres objets injectés, il a été constaté que l'objet n'était pas injecté et qu'il était nul.
Enfin, il a été constaté que la raison en était que la méthode était privée. Étant donné que Spring utilise JDK Dynamic Proxy ou CGLIB dynamic proxy, l'un est une classe qui implémente l'interface et l'autre est implémentée via des sous-classes. Ni l'interface ni la classe parent, la méthode privée ne peut être présente, sinon la sous-classe ni la classe d'implémentation ne peuvent être remplacées.
Si la méthode est privée, cette méthode ne peut pas être trouvée dans le processus de proxy, provoquant des problèmes dans la création d'objets proxy et provoquant l'injection de certains objets.
Donc, si la méthode doit utiliser des annotations AOP, définissez-la sur une méthode non privée.
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.