Spring AOP : Exemples de Programmation Orientée Aspects

Qu'est-ce que l'AOP ? Concepts de base Aspect : Obet spécial qui modélise les préoccupations transversales. Conseil : Travail que l'aspect doit accomplir. Chaque direction dans un aspect est appelée un conseil. Les conseils se trouvent dans les objets d'aspect. Cible : Objet qui est notifié. Proxy : Objet créé après avoir appliqué des conseils à l'objet cible.

Point de jonction : Emplacement spécifique dans l'exécution du programme de l'objet cible. Par exemple, avant ou après l'appel d'une méthode. Il inclut deux informations : 1. Quelle méthode du programme cible ? 2. La méthode s'exécute-t-elle avant ou après ? Point de coupe : Chaque classe aura plusieurs points de jonction, l'AOP localise des points de jonction spécifiques via des points de coupe. Par analogie, les points de jonction sont comme les enregistrements dans une base de données, tandis que les points de coupe sont comme les conditions de recherche. Un point de coupe correspond à plusieurs points de jonction.

Méthode de configuration XML :

1. Importation des bibliothèques Spring et des deux jar d'aspectj

2. Objet cible (l'objet à intercepter)

Tout d'abord, pour ne pas enfreindre le principe d'ouverture/fermeture et assurer une meilleure extensibilité, l'objet cible implémente en réalité une interface prédéfinie

Interface :

package com.example.spring.aop;

public interface IPersonne {
    public void manger();
    public void dormir();

}

Classes implémentant l'interface :

package com.example.spring.aop;

import org.springframework.stereotype.Component;

public class PersonneChinoise implements IPersonne {

    @Override
    public void manger() {
        System.out.println("Les Chinois mangent");

    }
    
    @Override
    public void dormir() {
        System.out.println("Les Chinois dorment");
    }

}

package com.example.spring.aop;

import org.springframework.stereotype.Component;


public class PersonneAmericaine implements IPersonne {

    @Override
    public void manger() {
        System.out.println("Les Américains mangent");

    }

    @Override
    public void dormir() {
        System.out.println("Les Américains dorment");
    }


}

3. Définition d'une classe d'aspect

package com.example.spring.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
public class AspectComportemental {
    
    public void avantManger(){
        System.out.println("Se laver les mains");
    }
    public void apresManger(){
        System.out.println("Se rincer la bouche");
    }
    public void avantDormir(){
        System.out.println("Se doucher");
        
    }

}

4. Configuration du fichier 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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"
        default-autowire="byName"
        >
         <!-- Instanciation des objets cibles et de la classe d'aspect -->
        <bean id="chinois" class="com.example.spring.aop.PersonneChinoise"></bean>
        <bean id="americain" class="com.example.spring.aop.PersonneAmericaine"></bean>
        <bean id="aspectComportemental" class="com.example.spring.aop.AspectComportemental"></bean>
        
        <aop:config>
        <!-- Objets à intercepter -->                 
        <aop:pointcut expression="execution(* com.example.spring.aop.*.manger(..))" id="pointManger"/>
        <aop:pointcut expression="execution(* com.example.spring.aop.*.dormir(..))" id="pointDormir"/>
        <!-- Points de coupe -->
        <aop:aspect id="comportement" ref="aspectComportemental"><!-- Classe d'aspect  -->
            <!--  <aop:before method="méthode de la classe d'aspect" pointcut-ref="point de coupe ci-dessus"/>  -->
            <aop:before method="avantManger()" pointcut-ref="pointManger"/><!-- Conseil avant -->
            <aop:after method="apresManger()" pointcut-ref="pointManger"/><!-- Conseil après -->
            <aop:before method="avantDormir()" pointcut-ref="pointDormir"/>
        </aop:aspect>
    </aop:config>
</beans>

5. Exécution

package com.example.spring.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationTest {

    public static void main(String[] args) {
        ApplicationContext contexte = new ClassPathXmlApplicationContext("beans.xml");
        // Utiliser l'interface pour la réception
        IPersonne p = (IPersonne)contexte.getBean("chinois");
        p.manger();
        p.dormir();
        System.out.println("*********************************");
        // Utiliser l'interface pour la réception
        IPersonne a= (IPersonne) contexte.getBean("americain");
        a.manger();
        a.dormir();

    }

}

Résultat :

Méthode utilisant les annotations :

1. Importation des bibliothèques Spring et des deux jar d'aspectj

2. Ajout de l'espace de noms aop dans le fichier de configurtaion

<?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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd" >

        <!-- Balayage automatique des classes dans le package et leur instanciation. Plusieurs packages séparés par , -->
        <context:component-scan base-package="com.example.spring.aop"></context:component-scan>
        <!-- Activation de la fonctionnalité d'annotation AspectJ dans le fichier de configuration, par défaut false, à changer en true -->
        <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> 
</beans>

3. Objet cible (l'objet à intercepter)

Tout d'abord, pour ne pas enfreindre le principe d'ouverture/fermeture et assurer une meilleure extensibilité, l'objet cible implémente en réalité une interface prédéfinie

Interface :

package com.example.spring.aop;

public interface IPersonne {
    public void manger();
    public void dormir();

}

Classes implémentant l'interface :

package com.example.spring.aop;

import org.springframework.stereotype.Component;

@Component
public class PersonneChinoise implements IPersonne {

    @Override
    public void manger() {
        System.out.println("Les Chinois mangent");

    }
    
    @Override
    public void dormir() {
        System.out.println("Les Chinois dorment");
    }

}

package com.example.spring.aop;

import org.springframework.stereotype.Component;

@Component
public class PersonneAmericaine implements IPersonne {

    @Override
    public void manger() {
        System.out.println("Les Américains mangent");

    }

    @Override
    public void dormir() {
        System.out.println("Les Américains dorment");
    }


}

4. Définition d'une classe d'aspect avec annotations directes

package com.example.spring.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect //Déclarer que cette classe est une classe d'aspect
@Component//Activer le balayage automatique dans la configuration
public class AspectComportemental {
    
    @Before("execution(* com.example.spring.aop.*.manger(..))")//Conseil avant la méthode spécifiée    * représente tout, .. représente tous les paramètres, peu importe leur nombre
    public void avantManger(){
        System.out.println("Se laver les mains");
    }
    @After("execution(* com.example.spring.aop.*.manger(..))")//Conseil après la méthode spécifiée
    public void apresManger(){
        System.out.println("Se rincer la bouche");
    }
    @Before("execution(* com.example.spring.aop.*.dormir(..))")
    public void avantDormir(){
        System.out.println("Se doucher");
        
    }

}

5. Écrire une fonction main pour exécuter

package com.example.spring.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationTest {

    public static void main(String[] args) {
        ApplicationContext contexte = new ClassPathXmlApplicationContext("beans.xml");
        PersonneChinoise p = contexte.getBean(PersonneChinoise.class);
        p.manger();
        p.dormir();
        System.out.println("*********************************");
        PersonneAmericaine a = contexte.getBean("americain", PersonneAmericaine.class);
        a.manger();
        a.dormir();

    }

}

Résultat :

Ainsi, la programmation orientée aspects de Spring est brièvement présentée.

Catégories de conseils : Conseil avant (@Before) -- Conseil exécuté avant l'exécution de la méthode cible. Conseil après (@After) -- Conseil exécuté après l'exécution de la méthode cible. Qu'une exception se produise ou non. Dans le conseil après, il est impossible de lire le résultat renvoyé par la méthode cible. Conseil de retour (@AfterReturnning) -- Conseil exécuté après l'exécution réussie de la méthode cible. Dans le conseil de retour, on peut accéder au résultat renvoyé par la méthode cible. @AfterReturnning(value="execution(* com.example.spring.aop..**(..))",returning="result") public void apresExecution(Object result){ System.out.println(result); }

Conseil d'exception (@AfterThrowing) -- Conseil exécuté lorsque la méthode cible génère une erreur. @AfterThrowing(value="execution(* com.example.spring.aop..**(..))",throwing="ex") public void apresException(Exception ex){ System.out.println(ex.getMessage()); }

Conseil entourant (@Around) -- Nécessite que la méthode d'aspect porte un paramètre ProceedingJoinPoint, similaire à un proxy dynamique complet. Le conseil entourant doit avoir une valeur de retour, qui est la valeur de retour de la méthode cible.

@Around("execution(* com.example.spring.aop..**(..))") public object conseilEntourant( ProceedingJoinPoint pjp){

Object obj = null; try{ //Effectuer le conseil avant obj = pjp.proceed(); //Effectuer le conseil de retour } catch(Exception ex){ //Effectuer le conseil d'exception } //Effectuer le conseil après return obj; }

Ajout de journaux :

La méthode d'aspect peut accepter un paramètre (JoinPoint) joinPoint.getSignature().getXXX() pour obtenir des informations sur la méthode La méthode d'aspect peut accepter un paramètre Object pour obtenir la valeur de retour de la méthode cible (uniquement applicable pour le conseil de retour)

Étiquettes: Spring AOP Programmation Orientée Aspects AspectJ Java

Publié le 11 juin à 19h49