Comprendre Spring AOP du point de vue de la configuration XML

Cet article est partagé par la communauté Huawei Cloud « Spring Master's Road 18 - Comprendre Spring AOP du point de vue de la configuration XML », auteur : Zhuan Yeyang__.

1. Spring AOP et proxy dynamique

1.1 Relation entre Spring AOP et proxy dynamique

Spring AOPImplémentez une programmation orientée aspect en utilisant des proxys dynamiques comme mécanisme principal. Ce mécanisme permet Springla création dynamique d'objets proxy au moment de l'exécution. Ces objets proxy encapsulent l'objet cible (c'est-à-dire le composant métier) pour insérer des comportements supplémentaires (tels que les contrôles de sécurité, la gestion des transactions, la journalisation, etc.) avant et après l'appel des méthodes de l'objet cible. .

  • Proxy dynamique JDKSpring AOP : Le proxy dynamique utilisé par défaut lorsque l'objet cible implémente une ou plusieurs interfaces JDK. JDKLe proxy dynamique utilise le mécanisme de réflexion pour créer un objet proxy pour l'interface. Cet objet proxy interceptera tous les appels à la méthode d'interface cible.

  • Proxy CGLIB : Si l'objet cible n'implémente aucune interface, Spring AOPil reviendra à utiliser CGLIBla bibliothèque pour générer une sous-classe de la classe cible. CGLIB( Code Generation Library) est une puissante bibliothèque de génération de code hautes performances qui étend Javales classes au moment de l'exécution et remplace les méthodes dans les sous-classes pour implémenter l'interception de méthodes.

Quelle que soit la méthode proxy utilisée, le but est d'insérer des comportements supplémentaires à différentes étapes de l'exécution de la méthode via des notifications définies par aspects sans modifier le code de logique métier d'origine.

1.2 Terminologie de base de l'AOP

Aspect : Aspect est au cœur de la programmation orientée aspect. C'est une construction qui modularise les préoccupations sur plusieurs classes (telles que la journalisation, la gestion des transactions, etc.). Un aspect peut contenir plusieurs types de conseils ( Advice) et un ou plusieurs points de coupe ( Pointcut) qui définissent où et quand ces conseils sont exécutés.

Point de jointure : Un point de jointure représente un emplacement spécifique lors de l'exécution du programme, Spring AOPlimitant ces emplacements aux appels de méthode. En termes simples, un point de jointure est un point où des conseils d'aspect peuvent être insérés.

Conseil : Le conseil définit l'action à effectuer par l'aspect au point de connexion. Selon le type de notification, ces actions peuvent être effectuées avant, après l'appel de la méthode, après le retour d'un résultat ou lorsqu'une exception est levée. Les types de notifications incluent :

  • Pré-notification ( Before advice) : exécutée avant l'exécution de la méthode.
  • Post-notification ( After advice) : exécuté après l'exécution de la méthode, quels que soient ses résultats.
  • Notification post-retour ( After-returning advice) : exécutée après l'exécution réussie de la méthode.
  • Notification post-exception ( After-throwing advice) : exécutée après que la méthode a levé une exception.
  • Conseil Surround ( Around advice) : exécuté avant et après l'exécution de la méthode, offrant un contrôle total sur les appels de méthode.

Pointcut (Pointcut) : Pointcut est une expression. Les expressions Pointcut permettent de faire correspondre les points de connexion via des noms de méthodes, des modificateurs d'accès et d'autres conditions, qui déterminent quelles méthodes doivent être déclenchées lorsque les notifications sont exécutées.

Objet cible : un objet qui est notifié par un ou plusieurs aspects. Également appelé objet mandaté.

AOP Proxy : AOPUn objet créé par le framework pour implémenter des contrats d'aspect (définis par des conseils et des pointscuts). Dans Spring AOP, AOPun proxy peut être JDKun proxy dynamique ou CGLIBun proxy.

Introduction : Introduction permet d'ajouter de nouvelles méthodes ou propriétés à une classe existante. Ceci est Introduction interfacesréalisé en définissant une ou plusieurs interfaces supplémentaires ( ), et AOPle framework crée un proxy pour l'objet cible qui implémente ces interfaces.

Si cela semble encore abstrait, donnons un autre exemple de production cinématographique par analogie.

Aspect

Imaginez que quelqu'un tourne un film et que les effets spéciaux du film (tels que des explosions et des effets d'éclairage spéciaux) sont comme des problèmes transversaux qui doivent être traités dans l'application (tels que la journalisation ou la gestion des transactions). Ces effets spéciaux apparaissent dans de nombreuses scènes différentes du film, pas seulement dans une scène spécifique. En AOPPython, ces « effets » sont des aspects, et ils peuvent être appliqués à plusieurs parties du programme sans changer la scène réelle (ou le code).

Rejoindre le point

Poursuivant la métaphore du film, un moment spécifique de chaque scène, comme le moment où une explosion se produit, peut être considéré comme un point de connexion. En programmation, cela correspond généralement à un appel de méthode.

Conseil

Les notifications sont comme des instructions spécifiques du réalisateur à l'équipe des effets spéciaux, telles que "Ajouter un effet d'explosion avant le début de cette scène" ou "Afficher l'effet de dissipation de la fumée après la fin de la scène". Ces instructions indiquent à l'équipe des effets spéciaux quels effets spécifiques doivent être ajoutés à des moments précis du film. Dans AOP, ces "instructions" sont des notifications, spécifiant que les aspects (effets spéciaux) doivent être exécutés avant, après ou autour des points de jointure (moments spécifiques d'exécution du code).

Point de coupe

Si l'avis est une instruction du réalisateur à l'équipe d'effets spéciaux, alors le point critique est les conditions spécifiques contenues dans l'instruction, telles que "scènes de tournage toute la nuit". Les pointcuts définissent quels points de connexion (tels que quels appels de méthode spécifiques) doivent recevoir des notifications (instructions d'effet).

Objet cible

Les objets cibles sont les scènes dans lesquelles des effets spéciaux doivent être ajoutés. Dans notre métaphore de programmation, ce sont les objets qui sont affectés par la logique des aspects (comme les classes qui nécessitent une journalisation).

Proxy AOP

AOPUn proxy est comme une copie virtuelle et contrôlable d’une scène fournie par l’équipe des effets spéciaux. Cette copie apparaît au public comme étant la même que la scène originale, mais en fait elle ajoute automatiquement des effets spéciaux lorsque le réalisateur en a besoin. En programmation, un proxy est un AOPobjet créé automatiquement par le framework. Il encapsule l'objet cible et garantit que les notifications (instructions d'effets spéciaux) sont exécutées au bon moment.

Introduction

L'introduction, c'est comme ajouter un tout nouveau personnage ou une toute nouvelle scène à un film qui n'existe pas dans le scénario original. Dans AOP, l'introduction nous permet d'ajouter de nouvelles méthodes ou propriétés à une classe existante, ce qui revient à étendre le contenu d'un film sans modifier le script original.

2. Implémentez Spring AOP via la configuration XML

SpringFournit AOPun support riche et peut XMLdéfinir des aspects, des notifications ( advice) et des points de coupe ( pointcuts) via la configuration. Cela vous permet d'ajouter des comportements supplémentaires (tels que la journalisation, la gestion des transactions, etc.) sans modifier le code source.

Étapes de mise en œuvre :

  1. Ajouter des dépendances Springpom.xml : ajoutez Springle framework et AOPles dépendances associées au projet .

  2. Définir des interfaces métier et des classes d'implémentation : Créez des interfaces de logique métier et leurs implémentations, comme une simple classe de service.

  3. Définir des classes d'aspect : créez une classe d'aspect pour définir les notifications avant, après et en boucle.

  4. Configuration XML : applicationContext.xmlconfigurez les aspects, les activités beanet AOPles balises associées en XML.

2.1 Ajouter une dépendance Spring

Dans pom.xmlle fichier, ajoutez les dépendances suivantes

<dépendances>
    <dépendance>
        <groupId>org.springframework</groupId>
        <artifactId>contexte de printemps</artifactId>
        <version>5.3.10</version>
    </dépendance>
    <dépendance>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.3.10</version>
    </dépendance>
    <dépendance>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.6</version>
    </dépendance>
</dépendances>

2.2 Définir les interfaces métier et les classes d'implémentation

Tout d'abord, nous définissons une interface logique métier MyServiceet sa mise en œuvre MyServiceImpl.

MonService.java :

paquet com.example.demo.aop ;
interface publique MonService {
    String performAction (String input) lève une exception ;
}

MonServiceImpl.java :

paquet com.example.demo.aop ;
classe publique MyServiceImpl implémente MyService {
    @Passer outre
    public String performAction (action String) lève une exception {
        System.out.println("Exécution d'une action dans MyService : " + action);
        if ("lancer".equals(action)) {
            throw new Exception("Exception de MyService");
        }
        return "Action effectuée : " + action ;
    }
}

2.3 Définir les classes d'aspect

Ensuite, nous définissons une classe d'aspect MyAspectqui contiendra un pré-avis ( advice) qui est exécuté avant l'exécution MyServicede la méthode.performAction

MonAspect.java :

paquet com.example.demo.aop ;

importer org.aspectj.lang.ProceedingJoinPoint ;

classe publique MonAspect {

    // pré-notification
    public void avantAdvice() {
        System.out.println("Avant que les conseils ne soient lancés !");
    }

    // poster une notification
    public void afterAdvice() {
        System.out.println("Après l'exécution des conseils !");
    }

    // Notifier après le retour
    public void afterReturningAdvice (Objet retVal) {
        System.out.println("Après le retour des conseils, le conseil est en cours d'exécution ! Valeur de retour : " + retVal);
    }

    // Notification après exception
    public void afterThrowingAdvice (Ex jetable) {
        System.out.println("Après le lancement, les conseils sont en cours d'exécution ! Exception : " + ex.getMessage());
    }

    //notification surround
    L'objet public aroundAdvice (ProceedingJoinPoint joinPoint) lance Throwable {
        System.out.println("A propos des conseils : avant l'exécution de la méthode");
        Résultat de l'objet = null ;
        essayer {
            résultat = joinPoint.proceed();
        } enfin {
            System.out.println("A propos des conseils : après l'exécution de la méthode");
        }
        renvoyer le résultat ;
    }
}

2.4 XML de configuration

Enfin, nous devons configurer le contenu ci-dessus et associé dans Springle fichier de configuration .applicationContext.xmlbeanAOP

applicationContext.xml :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--
Ce qui précède est la déclaration d'en-tête du fichier XML, qui définit la version et le type d'encodage du fichier, et introduit l'espace de noms des beans Spring et AOP.
Grâce à ces espaces de noms, nous pouvons utiliser les balises <bean> et <aop:*> en XML.
-->
    <!-- Définitions des beans -->
    <bean id="myService" class="com.example.demo.aop.MyServiceImpl"/>
    <bean id="myAspect" class="com.example.demo.aop.MyAspect"/>
	<!--Configuration AOP-->
    <aop:config>
        <!-- Définir les aspects et leurs notifications -->
        <aop:aspect id="myAspectRef" ref="myAspect">
            <!-- Définir les points de coupure et spécifier les notifications qui doivent être déclenchées lorsque les méthodes sont exécutées -->
            <aop:pointcut id="serviceOperation" expression="execution(* com.example.demo.aop.MyService.performAction(..))"/>
            <!-- Appliquer une pré-notification, spécifier les opérations avant l'exécution de la méthode -->
            <aop:before method="beforeAdvice" pointcut-ref="serviceOperation"/>
            <!-- Appliquer la post-notification, spécifier l'opération après l'exécution de la méthode, si la méthode est exécutée avec succès ou si une exception est levée -->
            <aop:after method="afterAdvice" pointcut-ref="serviceOperation"/>
            <!-- Notification après le retour de l'application, les opérations après que la méthode spécifiée a été exécutée et renvoyée avec succès -->
            <aop:after-returning method="afterReturningAdvice" pointcut-ref="serviceOperation" return="retVal"/>
            <!-- Notification après exception d'application, action après que la méthode spécifiée lève une exception -->
            <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="serviceOperation" throwing="ex"/>
            <!-- Appliquer les notifications environnantes pour fournir un contrôle complet avant et après l'exécution de la méthode -->
            <aop:around method="aroundAdvice" pointcut-ref="serviceOperation"/>
        </aop:aspect>
    </aop:config>
</haricots>

myService : Il s'agit d'une logique métier beanet pointe vers MyServiceImplune instance de la classe.

myAspect : Il s'agit d'un aspect beanpointant vers MyAspectune instance de la classe.

<aop:config>: Il s'agit AOPde l'élément racine de la configuration. Toutes AOPles configurations, y compris les définitions d'aspect, les points de coupe et les méthodes de notification, doivent être définies à l'intérieur de cet élément.

Aspect : Défini au travers <aop:aspect>d'éléments, il contient une série de conseils ( advice) et un ou plusieurs points de coupe ( pointcut). Cet élément associe des classes d'aspect (classes qui contiennent une logique de notification) à des opérations spécifiques (comment et quand améliorer l'objet cible).

Pointcut : Grâce à <aop:pointcut>la définition de l'élément, le pointcut est spécifié par expression. Lorsque vous devez contrôler précisément quelles méthodes déclencheront des notifications lors de leur exécution, vous devez définir le pointcut. Les expressions Pointcut peuvent spécifier des méthodes très précisément, par exemple par nom de méthode, types de paramètres, annotations, etc. expressionIl définit l'expression du pointcut et spécifie les règles de correspondance du pointcut. L'expression ici execution(* com.example.demo.aop.MyService.performAction(..))signifie que le pointcut correspond à l'exécution de la méthode MyServicedans l'interface performActionet que le pointcut est utilisé pour spécifier à quels points de connexion ( Join Pointtels que les appels de méthode) la notification est appliquée.

À propos de l'analyse des expressionsexecution(* com.example.demo.aop.MyService.performAction(..))

exécution : est la fonction pointcut la plus couramment utilisée, utilisée pour faire correspondre les points de connexion de l'exécution de la méthode.

* : Indique que le type de retour de la méthode est arbitraire.

com.example.demo.aop.MyService.performAction : Spécifie le chemin complet du nom de l'interface et du nom de la méthode.

(…) : Indique que les paramètres de la méthode sont arbitraires et correspondront quel que soit le nombre de paramètres de la méthode.

  • Point de jointure : Un point de jointure fait référence à un certain point lors de l'exécution d'un programme, tel qu'un appel de méthode. Les points de jointure sont identifiés et mis en correspondance  par des expressions pointcut ( ), qui définissent un pointcut qui spécifie un ensemble explicite de points de jointure, c'est-à-dire toutes les invocations de méthodes de l'interface . Dans cet exemple, les appels de méthode d'interface sont des points de connexion potentiels. Chaque fois qu'une méthode est appelée, un point de jointure est atteint . Ce point de connexion est l'endroit où l'application est informée de son timing.Pointcutexecution(* com.example.demo.aop.MyService.performAction(..))MyServiceperformActionMyServiceperformActionperformAction

  • Conseil : Il s'agit d'une AOPaction qui améliore l'exécution d'une méthode en effectuant des actions à des moments précis. methodL'attribut spécifie le nom de la méthode de l'aspect qui doit être exécuté lorsque le pointcut correspond, pointcut-reffaisant référence au pointcut défini ci-dessus. Par exemple, voici la méthode appelée avant l’exécution beforeAdvicede la méthode cible . performActionCela signifie que chaque fois qu’une MyService.performAction(..)méthode est appelée, beforeAdviceelle sera exécutée en premier.

Pour résumer en une phrase : Spring AOPen définissant des règles (points de coupure) dans des aspects pour spécifier quand (points de connexion) et comment (notifications) améliorer des méthodes spécifiques, la modularisation du code et la séparation des préoccupations sont obtenues sans modifier la logique métier d'origine. .

De cette manière, Spring AOP vous pouvez définir une logique personnalisée à insérer avant, après ou autour de l'exécution d'une méthode spécifique sans modifier le code de logique métier d'origine. Il s'agit d'un mécanisme puissant permettant de séparer les préoccupations, en particulier pour les préoccupations transversales qui couvrent plusieurs parties de l'application (telles que la journalisation, la gestion des transactions, etc.).

Notez que si <aop:config>réglé sur

<aop:config proxy-target-class="true">
    <!--Les autres configurations restent inchangées-->
</aop:config>

En définissant cela, le proxy proxy-target-class="true"sera Spring AOPutilisé de préférence CGLIBmême si l'objet cible implémente l'interface. Par défaut, proxy-target-classla propriété n'a pas besoin d'être définie, ou si elle est définie false, un proxy dynamique est utilisé JDK.

Programme principal :

DémoApplication.java :

paquet com.example.demo ;

importer com.example.demo.aop.MyService ;
importer org.springframework.context.support.ClassPathXmlApplicationContext ;

classe publique DemoApplication {
    public static void main (String[] arguments) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        MonService monService = (MonService) context.getBean("monService");

        essayer {
            System.out.println(myService.performAction("normal"));
        } attraper (Exception e) {
            e.printStackTrace();
        }

        System.out.println("=======================");

        essayer {
            System.out.println(myService.performAction("throw"));
        } attraper (Exception e) {
            System.out.println("Exception interceptée dans main : " + e.getMessage());
        }

        contexte.close();
    }
}

résultat de l'opération :

En combinant la technologie de proxy dynamique avec ces AOPconcepts, Spring AOPles applications peuvent prendre en charge des problèmes transversaux de manière non intrusive, permettant ainsi aux développeurs de modulariser ces problèmes et de garder les composants de logique métier ciblés et simples.

Si vous êtes intéressé par le proxy dynamique, vous pouvez le déboguer à nouveau. JDKLe proxy dynamique est ici car public class MyServiceImpl implements MyService l'interface est implémentée comme suit :

Parlons brièvement des classes et interfaces clés qui peuvent être vues ici.

ProxyFactory : Il s'agit Spring AOPd'une classe d'usine utilisée pour créer des objets proxy. Il peut décider d'utiliser JDKun proxy dynamique ou un proxy selon que l'objet cible implémente ou non l'interface CGLIB.

AopProxy : Cette interface définit des méthodes pour obtenir des objets proxy. Il a deux implémentations principales : JdkDynamicAopProxy(pour JDKles proxys dynamiques) et CglibAopProxy(pour CGLIBles proxys).

JdkDynamicAopProxy : Implémente AopProxyl'interface et utilise JDKla technologie de proxy dynamique pour créer un proxy. Il implémente InvocationHandlerl'interface et intercepte tous les appels de méthode à l'objet proxy.

CglibAopProxy : Implémente également AopProxyl'interface, mais utilise CGLIBune bibliothèque pour créer des objets proxy. Pour les classes qui n'implémentent pas l'interface, Springcette méthode sera choisie pour créer le proxy.

Si vous souhaitez comprendre Spring AOPle code source en profondeur, vous pouvez visualiser directement JdkDynamicAopProxyl' CglibAopProxyimplémentation de ces deux classes. Ce n’est pas l’objet de cet article, mentionnons simplement :

Par exemple, JdkDynamicAopProxyconsultez l'implémentation du proxy dynamique dans :

  1. JdkDynamicAopProxyLes classes implémentent InvocationHandlerdes interfaces, qui sont JDKau cœur du proxy dynamique. Dans sa invokeméthode, il y aura une logique pour déterminer si l'appel doit être intercepté, et les notifications correspondantes seront appliquées avant et après l'appel.

  2. Le processus de création d'un proxy se fait principalement ProxyFactoryen appelant createAopProxy()une méthode, qui renvoie une instance de JdkDynamicAopProxyou selon la configuration CglibAopProxy.

  3. Utilisation du proxy : Le code client ProxyFactoryobtient l'objet proxy et appelle la méthode cible via cet objet proxy. L'objet proxy utilise JdkDynamicAopProxyou en interne CglibAopProxypour intercepter ces appels et AOPeffectuer des notifications en fonction de la configuration. Le processus d' obtention ProxyFactoryd'un objet proxy Springse fait généralement implicitement dans la configuration et l'utilisation, notamment lors de l'utilisation de Springla gestion des conteneurs AOP. Ce processus ne nécessite pas que le développeur appelle ProxyFactorydirectement la classe. Lorsqu'un Springagent est défini dans la configuration beanet qu'un aspect lui est appliqué, Springle conteneur gère automatiquement le processus de création de l'agent et d'application des notifications. Ceci est réalisé grâce à la prise en charge Springdu post-processeur et AOPde l'espace de noms, et les développeurs n'ont généralement besoin que de configurer les aspects et les conseils de manière déclarative.

Si vous voulez voir CGLIBl'agent, 2voici un moyen

La troisième 1méthode consiste à supprimer l'interface MyServiceImplimplémentée , puis à modifier l'emplacement correspondant entre MyServicele programme principal et l'expression . La troisième méthode consiste à définir explicitement les propriétés de l'étiquette dans le fichier de configuration pour y parvenir. comme suit:expressionMyServiceImpl
2Spring<aop:config>proxy-target-class="true"

<aop:config proxy-target-class="true">
    <!--Les autres configurations restent inchangées-->
</aop:config>

Le débogage est le suivant :

 

Bienvenue dans la triple connexion en un clic ~

Si vous avez des questions, laissez un message et discutons et apprenons ensemble.

Cliquez pour suivre et découvrir les nouvelles technologies de Huawei Cloud dès que possible~

 

RustDesk a suspendu le service national Taobao (taobao.com) en raison d'une fraude généralisée, a repris le travail d'optimisation de la version Web, Apple a publié la puce M4, les lycéens ont créé leur propre langage de programmation open source en guise de cérémonie de passage à l'âge adulte - Les internautes ont commenté : S'appuyer sur Selon la défense, Yunfeng a démissionné d'Alibaba et envisage de produire à l'avenir la destination des programmeurs de jeux indépendants Visual Studio Code 1.89, a été officiellement annoncé par Huawei. L'ajustement du poste de Yu Chengdong a été cloué au « pilier de la honte FFmpeg ». « Il y a 15 ans, mais aujourd'hui il doit nous remercier - Tencent QQ Video venge sa honte précédente ? La station miroir open source de l'Université des sciences et technologies de Huazhong est officiellement ouverte à l'accès au réseau externe
{{o.name}}
{{m.nom}}

Je suppose que tu aimes

Origine my.oschina.net/u/4526289/blog/11106069
conseillé
Classement