Introduction aux expressions Pointcut au printemps

Introduction aux expressions Pointcut au printemps

1. Vue d'ensemble

Dans ce tutoriel, nous aborderons le langage d’expression Spring AOP de Spring AOP.

Nous allons d’abord introduire quelques termes utilisés dans la programmation orientée aspect. Unjoin point 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. Unpointcut est un prédicat qui correspond aux points de jointure et unpointcut expression language est une manière de décrire les pointcuts par programmation.

2. Usage

Une expression de découpe 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 est appelée lespointcut signature. Il fournit un nom qui peut être utilisé par les annotations de conseil pour faire référence à ce pointcut.

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

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


    

3. Désignateurs de coupe ponctuelle

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

3.1 execution

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

@Pointcut("execution(public String org.example.dao.FooDao.findById(Long))")

Cet exemple de coupe ponctuelle correspondra exactement à l'exécution de la méthodefindById de la classeFooDao. Cela fonctionne, mais ce n’est pas très flexible. Supposons que nous souhaitons faire correspondre toutes les méthodes de la classeFooDao, 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(* org.example.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 within

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

@Pointcut("within(org.example.dao.FooDao)")

Nous pourrions également faire correspondre n'importe quel type dans le packageorg.example ou dans un sous-package.

@Pointcut("within(org.example..*)")

3.3 this and target

this limite la correspondance aux points de jointure où la référence de bean est une instance du type donné, tandis quetarget 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 PCDtarget car l'objet mandaté sera une instance de la classeProxy et implémentera l'interfaceBarDao:

@Pointcut("target(org.example.dao.BarDao)")

D'un autre côté, siFooDao n'implémente aucune interface ou que la propriétéproxyTargetClass est définie sur true, alors l'objet mandaté sera une sous-classe deFooDao et le PCD dethis pourrait être utilisé:

@Pointcut("this(org.example.dao.FooDao)")

3.4 args

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 typeLong. Si nous voulons faire correspondre une méthode avec un nombre quelconque de paramètres mais ayant le premier paramètre de typeLong, nous pourrions utiliser l'expression suivante:

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

3.5 @target

Le PCD@target (à ne pas confondre avec le PCDtarget 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 jonction où le type d'exécution des arguments réels transmis possède 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(org.example.aop.annotations.Entity)")
public void methodsAcceptingEntities() {}

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

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

3.7 @within

Ce PCD limite la correspondance avec des points de jonction 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 jonction où le sujet du point de jonction a l'annotation donnée. Par exemple, nous pouvons créer une annotation@Loggable:

@Pointcut("@annotation(org.example.aop.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 à l'aide des opérateurs&&,|| et!:

@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 points de coupe, nous avons illustré quelques exemples d'utilisation d'expressions en points de coupe.

L'ensemble complet d'exemples peut être trouvé dansmy github project - il s'agit d'un projet basé sur Eclipse, il devrait donc être facile à importer et à exécuter tel quel.