Les notifications de printemps AOP sont divisées en cinq catégories:
Avant les conseils: exécutez-vous devant le point de connexion. L'aperçu n'affectera pas l'exécution du point de connexion à moins qu'une exception ne soit lancée ici.
Notification de retour normale [Une fois les conseils de retour]: Exécuter une fois l'exécution normale du point de connexion terminée. Si une exception est lancée par le point de connexion, elle ne sera pas exécutée.
Exception Retour Notification [Après les conseils de lancement]: Exécutez après une exception lancée par le point de connexion.
Notification de retour [après (enfin) conseil]: Une fois l'exécution terminée, le contenu de la notification de retour sera exécuté s'il est terminé normalement ou si une exception est lancée.
Autour des conseils: autour des conseils entourent le point de connexion, comme avant et après un appel de méthode. Il s'agit du type de notification le plus puissant, qui peut personnaliser certaines opérations avant et après les appels de méthode.
La notification environnante doit également décider de continuer à traiter le point de jointure (appelant la méthode de processus du procédure joinpoint) ou d'interrompre l'exécution.
Ensuite, nous testerons cinq types de notification en écrivant un exemple de programme:
Définir l'interface
Package com.chenqa.springaop.example.service; interface publique BankService {/ ** * Transfert bancaire simulé * @param du compte * @param au compte * @param Montant de transfert de compte * @return * / transfert de booléen public (formulaire de chaîne, chaîne à, double compte);};Écrire des classes d'implémentation
Package com.chenqa.springaop.example.service.impl; import com.chenqa.springaop.example.service.bankService; classe publique BCMBankServiceImplt implémente BankService {Public Boolean Transfert (String Form, String to, Double compte) " yuan "); } System.out.println (form + "Transfer vers" + vers + "Compte bancaire" + compte + "yuan"); retourne false; }}Modifiez le fichier de configuration de ressort et ajoutez ce qui suit:
<! - BankService bean -> <bean id = "BankService" /> <! - Section -> <bean id = "myaspect" /> <! - AOP Configuration -> <aop: config> <aop: aspect ref = "Myaspect"> <aop: Pointcut Expression = "Execution (* com.chenqa.springaop.example.Service.Immpl. id = "Pointcut" /> <aop: avant méthode = "avant" Pointcut-ref = "Pointcut" /> <aop: après méthode = "After" Pointcut-Ref = "Pointcut" /> <aop: après-retour méthode = "After-Rerenting" <aop: autour de la méthode = "autour" Pointcut-ref = "Pointcut" /> </aop: aspect> </aop: config>
Rédaction d'un programme de test
ApplicationContext context = new ClassPathxMlApplicationContext ("Spring-aop.xml"); BankService BankService = context.getBean ("BankService", BankService.class); BankService.Transfer ("Zhang San", "Li Si", 200); Sortie après exécution:
Changez 200 dans le programme de test à 50, puis sortie après l'exécution:
D'après les résultats des tests, on peut voir que l'ordre d'exécution des cinq notifications est:
Pré-notification → Notification surround → Notification de retour normale / Retour d'exception Notification → Retour Notification, vous pouvez effectuer plusieurs fois à afficher.
Cas 1: Une méthode n'est interceptée que par une classe d'aspect
Lorsqu'une méthode est interceptée par un seul aspect, dans quel ordre les différents conseils de cet aspect sont-ils exécutés? Veuillez voir:
Ajouter la classe Pointcut
Cette coupe de points est utilisée pour intercepter toutes les méthodes dans toutes les classes dans le package de test.
Test de package; import org.aspectj.lang.annotation.pointcut; public class PointCuts {@pointcut (value = "dans (test. *)") public void aopdemo () {}}Ajouter une classe d'aspect
Les conseils dans cette classe utiliseront la coupe de points ci-dessus. Veuillez vous référer à l'attribut de valeur de chaque conseil lorsque vous l'utilisez.
Test de package; import org.aspectj.lang.joinpoint; import org.aspectj.lang.proceedingjoinpoint; import org.aspectj.lang.annotation. *; import org.springframework.sterreotype. {System.out.println ("[Aspect1] Avant les conseils"); } @Around (value = "test.pointcuts.aopDemo ()") public void Around (procédingjoinpoint pjp) lance throwable {System.out.println ("[aspect1] autour des conseils 1"); pjp.proceed (); System.out.println ("[Aspect1] autour de conseils2"); } @Afterreturning (value = "test.pointcuts.aopDemo ()") public void afterreturning (joinpoint joinpoint) {System.out.println ("[Aspect1] après le retour des conseils"); } @AfterThrowrowing (value = "test.pointcuts.aopdemo ()") public void after-throwing (joinpoint joinpoint) {System.out.println ("[aspect1] Conseils après la mise en scène"); } @After (value = "test.pointcuts.aopdemo ()") public void after (joinpoint joinpoint) {System.out.println ("[Aspect1] After-throwing conseils"); } @After (value = "test.pointcuts.aopdemo ()") public void after (joinpoint joinpoint) {System.out.println ("[aspect1] après conseiller"); }}Ajouter un contrôleur de test
Ajoutez un contrôleur pour les tests. Il n'y a qu'une seule méthode dans ce contrôleur, mais elle s'occupera différemment en fonction des valeurs des paramètres: l'une consiste à renvoyer un objet normalement, et l'autre est de lancer une exception (car nous voulons tester les conseils @AfterThrowing)
Test de package; Import Test.Exception.TesTexception; Import org.springframework.http.httpstatus; import org.springframework.web.bind.annotation. *; @ restController @ requestmapping (value = "/ aop") public Class AoptestController {@ResponSesatAt (HTTPSTATUS.OOK) = "/ test", méthode = requestMethod.get) Test de résultat public (@RequestParam Boolean ThrowException) {// Case 1 if (throwException) {System.out.println ("Throw une exception"); lancer un nouveau TestException ("Mock A Server Exception"); } // case 2 system.out.println ("test ok"); return nouveau résultat () {{this.setid (111); this.setName ("Mock A Result"); }}; } Résultat de classe statique publique {private int id; nom de chaîne privé; public int getID () {return id; } public void setid (int id) {this.id = id; } public String getName () {Nom de retour; } public void setName (string name) {this.name = name; }}}Tester la situation normale
Entrez directement l'URL suivante dans le navigateur et entrez: http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=false 1
Nous verrons le résultat de sortie:
[Aspect1] autour des conseils 1 [Aspect1] avant les conseils ok [aspect1] autour de conseils2 [Aspect1] après conseil [Aspect1] après avoir remis des conseils
Tester les exceptions
Entrez directement l'URL suivante dans le navigateur et appuyez sur Entrée: http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=true 1
Nous verrons le résultat de sortie:
[Aspect1] autour des conseils 1 [Aspect1] avant de conseiller une exception [Aspect1] après les conseils [Aspect1] Conseils après la prise
en conclusion
Lorsqu'une méthode est interceptée par une seule classe d'aspect, les conseils à l'intérieur de la classe d'aspect seront exécutés dans l'ordre suivant:
Situation normale:
Exception:
Cas 2: La même méthode est interceptée par plusieurs classes d'aspect
Voici un exemple qui est intercepté par deux classes d'aspect.
Dans certains cas, pour deux classes d'aspects différentes, que leurs conseils utilisent la même coupe de points ou de points de point différents, cela peut entraîner l'interception de la même méthode par plusieurs classes d'aspect. Donc, dans ce cas, dans quel ordre les conseils de ces classes d'aspect multiples exécutent-ils? Veuillez voir:
La classe de points de point reste inchangée
Ajouter une nouvelle classe d'aspect
Test de package; import org.aspectj.lang.joinpoint; import org.aspectj.lang.proceedingjoinpoint; import org.aspectj.lang.annotation. *; import org.springframework.sterreotype. {System.out.println ("[Aspect2] Avant les conseils"); } @Around (value = "test.pointcuts.aopDemo ()") public void Around (procédingjoinpoint pjp) lance throwable {System.out.println ("[aspect2] autour de conseils 1"); pjp.proceed (); System.out.println ("[Aspect2] autour de conseils2"); } @Afterreturning (value = "test.pointcuts.aopDemo ()") public void afterreturning (joinpoint joinpoint) {System.out.println ("[Aspect2] après le retour des conseils"); } @AfterThrowrowing (value = "test.pointcuts.aopdemo ()") public void after-throwing (joinpoint joinpoint) {System.out.println ("[Aspect2] Conseils après la mise en scène"); } @After (value = "test.pointcuts.aopDemo ()") public void after (joinpoint joinpoint) {System.out.println ("[Aspect2] After-throwing conseils"); } @After (value = "test.pointcuts.aopdemo ()") public void après (joinpoint joinpoint) {System.out.println ("[aspect2] après conseiller"); }}Le contrôleur de test est également inchangé
Utilisez toujours le contrôleur ci-dessus. Mais maintenant, Aspect1 et Aspect2 interceptent les méthodes du contrôleur.
Continuez à tester ci-dessous!
Tester la situation normale
Entrez directement l'URL suivante dans le navigateur et entrez: http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=false 1
Nous verrons le résultat de sortie:
[Aspect2] autour des conseils 1 [Aspect2] Avant les conseils [Aspect1] autour des conseils 1 [Aspect1] Avant les conseils ok [Aspect1] autour de conseils2 [Aspect1] après conseil [Aspect1] après avoir remis des conseils [Aspect2] autour des conseils2 [Aspect2] après avoir remis des conseils
Mais pour le moment, je ne peux pas conclure que l'aspect2 est définitivement exécuté avant Aspect1.
Vous ne le croyez pas? Vous redémarrez le serveur et réessayez, peut-être que vous verrez les résultats d'exécution suivants:
[Aspect1] autour des conseils 1 [Aspect1] Avant les conseils [Aspect2] autour des conseils 1 [Aspect2] Avant les conseils ok [Aspect2] autour des conseils2 [Aspect2] après les conseils [Aspect2] après avoir remis des conseils [Aspect1] autour des conseils2 [Aspect1] après avoir remis des conseils
Autrement dit, dans ce cas, l'ordre d'exécution de l'aspect1 et de l'aspect2 est inconnu. Alors, comment le résoudre? Pas pressé, la solution sera donnée ci-dessous.
Tester les exceptions
Entrez directement l'URL suivante dans le navigateur et appuyez sur Entrée: http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=true 1
Nous verrons le résultat de sortie:
[Aspect2] autour des conseils 1 [Aspect2] avant les conseils [Aspect1] autour des conseils 1 [Aspect1] avant de conseiller une exception [Aspect1] après avoir lancé des conseils [Aspect2] après avoir lancé des conseils
De même, si vous redémarrez le serveur, puis le testez à nouveau, vous pouvez voir les résultats suivants:
[Aspect1] autour des conseils 1 [Aspect1] Avant les conseils [Aspect2] autour des conseils 1 [Aspect2] avant de prédire une exception [Aspect2] Conseils après la prise
C'est-à-dire, de la même manière, l'ordre d'exécution de l'aspect1 et de l'aspect2 est également indéterminé dans des circonstances exceptionnelles.
Donc, dans le cas 2, comment spécifiez-vous l'ordre d'exécution de chaque aspect?
Il existe deux méthodes:
Quelle que soit la méthode utilisée, plus l'aspect est petit, plus il est exécuté en premier.
Par exemple, nous ajoutons respectivement des annotations @Order pour APSECT1 et Aspect2, comme suit:
@Order (5) @ Component @ AspectPublic Class Aspect1 {// ...} @ Order (6) @ Component @ AspectPublic classe Aspect2 {// ...} Après cette modification, il peut être assuré qu'en tout cas, les conseils dans Aspect1 sont toujours exécutés avant les conseils dans Aspect2. Comme indiqué dans la figure ci-dessous:
Note
Si deux conseils identiques sont définis pour la même coupe de points (par exemple, deux @Before) sont définis, alors l'ordre d'exécution de ces deux conseils ne peut pas être déterminé, même si vous ajoutez l'annotation @Order à ces deux conseils, cela ne fonctionnera pas. Rappelez-vous cela.
Pour les conseils @around, qu'il ait ou non une valeur de retour, il doit appeler pjp.proceed () à l'intérieur de la méthode; Sinon, l'interface du contrôleur ne sera pas exécutée, ce qui entraînera également le déclenchement du Conseil @Before. Par exemple, nous supposons que dans des circonstances normales, l'ordonnance d'exécution est "Aspect2 -> apsect1 -> contrôleur". Si nous supprimons pjp.proceed (); Dans @Around dans Aspect1, alors la sortie que nous voyons sera:
[Aspect2] autour des conseils 1 [Aspect2] Avant les conseils [Aspect1] autour des conseils 1 [Aspect1] autour des conseils2 [Aspect1] après conseil [Aspect1] après avoir remis des conseils [Aspect2] autour des conseils2 [Aspect2] après avoir remis des conseils
D'après les résultats, nous pouvons constater que l'interface dans le contrôleur n'a pas été exécutée et que @BeForEadvice dans Aspect1 n'a pas non plus été exécuté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.