Introduction à Spring AOP : Concepts fondamentaux

Introduction à la programmation orientée aspect avec Spring

  1. Compréhension du concept

La programmation orientée aspect (AOP) permet d'ajouter des fonctionnalités transversales à une application sans modifier le code source existant. L'idée principale consiste à injecter des comportements supplémentaires à certains points du flux d'exécution, sans polluer la logique métier principale.

Avantages

  • Découplage du code : les fonctionnalités transversales sont isolées dans des aspects distincts.
  • Maintenabilité : chaque préoccupations est gérer de manière indépendante.
  • Réutilisabilité : les aspects peuvent être appliqués à plusieurs modules.
  1. Terminologie essentielle

Prenons l'exemple d'un inspecteur qui vérifie les compteurs électriques chez les abonnés.

Conseil (Advice) :

L'inspecteur sait quelles tâches effectuer et à quel moment. De même, un advice définit quoi faire et quand l'exécuter dans le contexte d'un aspect.

Cinq types de conseil existent
  1. Before : s'exécute avant la méthode cible.
  2. After : s'exécute après la méthode目标, quelle que soit l'issue.
  3. After-returning : s'exécute après le succès de la méthode.
  4. After-throwing : s'exécute si une exception est levée.
  5. Around : enveloppe l'exécution de la méthode, permettant d'intervenir avant et après.

Point de jointure (Join Point) :

Chaque habitation peut être inspectée. Dans une application, les points de jointure représentent les moments où un aspect peut s'intercaler : appels de méthodes, levées d'exceptions, etc.

Point de coupe (Pointcut) :

Un inspecteur ne visite pas tous les abonnés. Les pointcuts permettent de sélectionner précisément quels points de jointure seront affectés par un aspect. Ils définissent le « où » à travers des expressions de correspondantion sur les noms de classes et méthodes.

Aspect :

L'aspect combine le conseil (quoi faire) et le pointcut (où le faire). C'est l'unité modulaire qui encapsule le comportement transversal.

Introduction :

Cette fonctionnalité permet d'ajouter de nouvelles méthodes ou propriétés à des classes existantes sans modification directe du code source.

  1. Support Spring AOP

Spring implémente AOP en utilisant des proxys dynamiques au moment de l'exécution. Le framewokr ne gère que les points de jointure au niveau des méthodes. Cette approche offre une intégration transparente avec le conteneur IoC de Spring.

  1. Expressions de pointcut avec AspectJ

Spring utilise la syntaxe AspectJ pour définir les pointcuts :

Indicateur Description
args() Correspond aux méthodes dont les paramètres sont d'un type spécifié
@args() Correspond aux méthodes dont les paramètres sont annotés
execution() Définit la correspondance principale
this() Correspond aux beans proxy d'un type donné
target() Correspond aux objets cibles d'un type spécifié
@target() Correspond aux objets annotés d'un type donné
within() Limite la correspondance à un package
@within() Correspond aux classes annotées
@annotation Correspond aux éléments annotés

L'indicateur execution est le seul qui effectue réellement la correspondance ; les autres servent de filtres.

4.1 Exemple pratique

Configuration Maven nécessaire :

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.9</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.9</version>
</dependency>

Définition d'une interface de service :

public interface ServiceCalcul {
    int calculer(int valeur);
}

Expression de pointcut permettant d'intercepter l'appel :

execution(* math.ServiceCalcul.calculer(..))

Explications :

  • execution : interception au moment de l'exécution
  • ***** : tout type de retour
  • math.ServiceCalcul : classe cible
  • calculer : méthode concernée
  • (..) : peu importe les paramètres

Limitation de la portée avec with in :

execution(* math.ServiceCalcul.calculer(..))
    && within(math.*)

4.2 Sélection par bean

L'indicateur bean permet de cibler un bean spécifique par son identifiant :

execution(* math.ServiceCalcul.calculer())
&& bean('calculateurPrincipal')

4.3 Création d'un aspect avec annotations

Les annotations AspectJ simplifient considérablement la déclaration des aspects.

Définition de l'aspect pour un service de logging :

package com.example.math;

import org.aspectj.lang.annotation.*;

@Aspect
public class Journaliseur {
    
    @Before("execution(* com.example.math.ServiceCalcul.calculer(..))")
    public void initialiserJournal() {
        System.out.println("Démarrage du calcul");
    }

    @Before("execution(* com.example.math.ServiceCalcul.calculer(..))")
    public void verifierParametres() {
        System.out.println("Vérification des paramètres");
    }

    @AfterReturning("execution(* com.example.math.ServiceCalcul.calculer(..))")
    public void enregistrerResultat() {
        System.out.println("Calcul terminé avec succès");
    }

    @AfterThrowing("execution(* com.example.math.ServiceCalcul.calculer(..))")
    public void gererErreur() {
        System.out.println("Une erreur s'est produite");
    }
}

Configuration Spring :

@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class ConfigurationApplication {
    
    @Bean
    public Journaliseur journaliseur() {
        return new Journaliseur();
    }
    
    @Bean
    public ServiceCalcul calculateur() {
        return new CalculateurImplementation();
    }
}

Implémentation du service :

package com.example.math;

public class CalculateurImplementation implements ServiceCalcul {
    @Override
    public int calculer(int valeur) {
        System.out.println("Exécution du calcul pour : " + valeur);
        return valeur * 2;
    }
}

Test d'exécution :

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class ProgrammeTest {
    public static void main(String[] args) {
        ApplicationContext contexte = new AnnotationConfigApplicationContext("com.example.math");
        ServiceCalcul service = contexte.getBean(ServiceCalcul.class);
        int resultat = service.calculer(5);
    }
}

Résultat obtenu :

Démarrage du calcul Vérification des paramètres Exécution du calcul pour : 5 Calcul terminé avec succès

Étiquettes: Spring AOP Java aspect AspectJ

Publié le 13 juin à 06h02