Introduction aux expressions ponctuelles au printemps

1. Vue d'ensemble

Dans ce didacticiel, nous aborderons le langage d'expression pointcut Spring AOP.

Nous allons d'abord introduire une certaine terminologie utilisée dans la programmation orientée aspect. Un point de jointure est une étape de l'exécution du programme, telle que l'exécution d'une méthode ou la gestion d'une exception. Dans Spring AOP, un point de jointure représente toujours une exécution de méthode. Un pointcut est un prédicat qui correspond aux points de jointure et un langage d'expression de pointcut est un moyen de décrire les pointcuts par programme.

2. Utilisation

Une expression de coupe par point peut apparaître comme une valeur de l' annotation @Pointcut :

@Pointcut("within(@org.springframework.stereotype.Repository *)") public void repositoryClassMethods() {}

La déclaration de méthode s'appelle la signature de coupe ponctuelle . Il fournit un nom qui peut être utilisé par les annotations de conseils pour faire référence à ce point.

@Around("repositoryClassMethods()") public Object measureMethodExecutionTime(ProceedingJoinPoint pjp) throws Throwable { ... }

Une expression pointcut peut également apparaître comme la valeur de la propriété expression d'une balise aop: pointcut :

3. Désignateurs de pointes

Une expression de coupe de point commence par un désignateur de coupe de point (PCD) , qui est un mot-clé indiquant à Spring AOP ce qu'il faut faire correspondre. Il existe plusieurs désignateurs de pointure, tels que l'exécution d'une méthode, un type, des arguments de méthode ou des annotations.

3.1 exécution

Le PCD Spring principal est l' exécution , qui correspond aux points de jonction d'exécution de méthode.

@Pointcut("execution(public String com.baeldung.pointcutadvice.dao.FooDao.findById(Long))")

Cet exemple de coupe ponctuelle correspondra exactement à l'exécution de la méthode findById de la classe FooDao . Cela fonctionne, mais ce n'est pas très flexible. Supposons que nous souhaitons faire correspondre toutes les méthodes de la classe FooDao , qui peuvent avoir des signatures, des types de retour et des arguments différents. Pour ce faire, nous pouvons utiliser des caractères génériques:

@Pointcut("execution(* com.baeldung.pointcutadvice.dao.FooDao.*(..))")

Ici, le premier caractère générique correspond à n'importe quelle valeur de retour, le second correspond à n'importe quel nom de méthode et le modèle (..) correspond à n'importe quel nombre de paramètres (zéro ou plus).

3.2 dans

Une autre façon d'obtenir le même résultat que dans la section précédente consiste à utiliser dans PCD, qui limite la correspondance avec les points de jointure de certains types.

@Pointcut("within(com.baeldung.pointcutadvice.dao.FooDao)")

Nous pouvons également faire correspondre n'importe quel type dans le package com.baeldung ou dans un sous-package.

@Pointcut("within(com.baeldung..*)")

3.3 ceci et cible

cela limite la correspondance aux points de jointure où la référence de bean est une instance du type donné, tandis que la cible limite la correspondance aux points de jointure où l'objet cible est une instance du type donné. Le premier fonctionne lorsque Spring AOP crée un proxy basé sur CGLIB, et le dernier est utilisé lorsqu'un proxy basé sur JDK est créé. Supposons que la classe cible implémente une interface:

public class FooDao implements BarDao { ... }

Dans ce cas, Spring AOP utilisera le proxy basé sur JDK et vous devez utiliser le PCD cible car l'objet proxy sera une instance de la classe Proxy et implémentera l' interface BarDao :

@Pointcut("target(com.baeldung.pointcutadvice.dao.BarDao)")

D'autre part , si FooDao ne met pas en œuvre une interface ou proxyTargetClass propriété est définie sur true, l'objet sera une approximé sous - classe de FooDao et ce PCD pourrait être utilisé:

@Pointcut("this(com.baeldung.pointcutadvice.dao.FooDao)")

3.4 arguments

Ce PCD est utilisé pour faire correspondre des arguments de méthode particuliers:

@Pointcut("execution(* *..find*(Long))")

Ce pointcut correspond à toute méthode qui commence par find et n'a qu'un seul paramètre de type Long . Si nous voulons faire correspondre une méthode avec un nombre quelconque de paramètres mais ayant le premier paramètre de type Long , nous pourrions utiliser l'expression suivante:

@Pointcut("execution(* *..find*(Long,..))")

3.5 @target

Le PCD @target (à ne pas confondre avec le PCD cible décrit ci-dessus) limite la correspondance aux points de jointure où la classe de l'objet en cours d'exécution a une annotation du type donné:

@Pointcut("@target(org.springframework.stereotype.Repository)")

3.6 @args

Ce PCD limite la correspondance aux points de jointure où le type d'exécution des arguments réels passés a des annotations du ou des types donnés. Supposons que nous voulions tracer toutes les méthodes acceptant les beans annotés avec l' annotation @Entity :

@Pointcut("@args(com.baeldung.pointcutadvice.annotations.Entity)") public void methodsAcceptingEntities() {}

Pour accéder à l'argument, nous devons fournir un argument JoinPoint au conseil:

@Before("methodsAcceptingEntities()") public void logMethodAcceptionEntityAnnotatedBean(JoinPoint jp) { logger.info("Accepting beans with @Entity annotation: " + jp.getArgs()[0]); }

3.7 @dans

Ce PCD limite la correspondance aux points de jointure dans les types qui ont l'annotation donnée:

@Pointcut("@within(org.springframework.stereotype.Repository)")

Ce qui équivaut à:

@Pointcut("within(@org.springframework.stereotype.Repository *)")

3.8 @annotation

Ce PCD limite la correspondance aux points de jointure où le sujet du point de jointure a l'annotation donnée. Par exemple, nous pouvons créer une annotation @Loggable :

@Pointcut("@annotation(com.baeldung.pointcutadvice.annotations.Loggable)") public void loggableMethods() {}

Ensuite, nous pouvons enregistrer l'exécution des méthodes marquées par cette annotation:

@Before("loggableMethods()") public void logMethod(JoinPoint jp) { String methodName = jp.getSignature().getName(); logger.info("Executing method: " + methodName); }

4. Combinaison d'expressions de découpe

Les expressions de point de coupe peuvent être combinées avec && , || et ! les opérateurs:

@Pointcut("@target(org.springframework.stereotype.Repository)") public void repositoryMethods() {} @Pointcut("execution(* *..create*(Long,..))") public void firstLongParamMethods() {} @Pointcut("repositoryMethods() && firstLongParamMethods()") public void entityCreationMethods() {}

5. Conclusion

Dans cette introduction rapide à Spring AOP et aux pointcuts, nous avons illustré quelques exemples d'utilisation d'expressions pointcut.

L'ensemble complet d'exemples est disponible à l'adresse over sur GitHub.