Introduction à AspectJ

1. Introduction

Cet article est une introduction rapide et pratique à AspectJ.

Tout d'abord, nous montrerons comment activer la programmation orientée aspect, puis nous nous concentrerons sur la différence entre le tissage au moment de la compilation, de la post-compilation et du chargement.

Commençons par une brève introduction de la programmation orientée aspect (AOP) et des bases d'AspectJ.

2. Aperçu

AOP est un paradigme de programmation qui vise à accroître la modularité en permettant la séparation des préoccupations transversales. Il le fait en ajoutant un comportement supplémentaire au code existant sans modification du code lui-même. Au lieu de cela, nous déclarons séparément le code à modifier.

AspectJ met en œuvre à la fois des préoccupations et le tissage de préoccupations transversales en utilisant des extensions du langage de programmation Java.

3. Dépendances de Maven

AspectJ propose différentes bibliothèques en fonction de son utilisation. Nous pouvons trouver les dépendances Maven sous le groupe org.aspectj dans le référentiel Maven Central.

Dans cet article, nous nous concentrons sur les dépendances nécessaires pour créer des aspects et Weaver en utilisant les Weavers au moment de la compilation, de la post-compilation et du chargement.

3.1. AspectJ Runtime

Lors de l'exécution d'un programme AspectJ, le chemin des classes doit contenir les classes et les aspects ainsi que la bibliothèque d'exécution AspectJ aspectjrt.jar :

 org.aspectj aspectjrt 1.8.9 

Cette dépendance est disponible sur Maven Central.

3.2. AspectJWeaver

Outre la dépendance d'exécution AspectJ, nous devrons également inclure l' aspectjweaver.jar pour présenter des conseils à la classe Java au moment du chargement:

 org.aspectj aspectjweaver 1.8.9 

La dépendance est également disponible sur Maven Central.

4. Création d'aspect

AspectJ fournit une implémentation d'AOP et a trois concepts de base:

  • Rejoindre le point
  • Pointcut
  • Conseil

Nous allons démontrer ces concepts en créant un programme simple pour valider le solde d'un compte utilisateur.

Tout d'abord, créons une classe de compte avec un solde donné et une méthode de retrait:

public class Account { int balance = 20; public boolean withdraw(int amount) { if (balance < amount) { return false; } balance = balance - amount; return true; } }

Nous allons créer un fichier AccountAspect.aj pour enregistrer les informations du compte et valider le solde du compte (notez que les fichiers AspectJ se terminent par une extension de fichier « .aj »):

public aspect AccountAspect { final int MIN_BALANCE = 10; pointcut callWithDraw(int amount, Account acc) : call(boolean Account.withdraw(int)) && args(amount) && target(acc); before(int amount, Account acc) : callWithDraw(amount, acc) { } boolean around(int amount, Account acc) : callWithDraw(amount, acc) { if (acc.balance < amount) { return false; } return proceed(amount, acc); } after(int amount, Account balance) : callWithDraw(amount, balance) { } }

Comme nous pouvons le voir, nous avons ajouté un pointcut à la méthode de retrait et créé trois conseils qui font référence au pointcut défini .

Afin de comprendre ce qui suit, nous introduisons les définitions suivantes:

  • Aspect : Une modularisation d'une préoccupation qui traverse plusieurs objets. Chaque aspect se concentre sur une fonctionnalité transversale spécifique
  • Point de jointure : point lors de l'exécution d'un script, tel que l'exécution d'une méthode ou l'accès à une propriété
  • Conseil : action entreprise par un aspect à un point de jonction particulier
  • Pointcut : une expression régulière qui correspond aux points de jointure. Un conseil est associé à une expression de point de coupe et s'exécute à tout point de jointure correspondant au point de coupe

Pour plus de détails sur ces concepts et leur sémantique spécifique, nous pouvons consulter le lien suivant.

Ensuite, nous devons intégrer les aspects dans notre code. Les sections ci-dessous traitent de trois types de tissage différents: le tissage à la compilation, le tissage après la compilation et le tissage au chargement dans AspectJ.

5. Tissage au moment de la compilation

L'approche la plus simple du tissage est le tissage au moment de la compilation. Lorsque nous avons à la fois le code source de l'aspect et le code dans lequel nous utilisons les aspects, le compilateur AspectJ compilera à partir des sources et produira des fichiers de classe tissés en sortie. Ensuite, lors de l'exécution de votre code, la classe de sortie du processus de tissage est chargée dans JVM en tant que classe Java normale.

Nous pouvons télécharger les outils de développement AspectJ car ils incluent un compilateur AspectJ fourni. L'une des fonctionnalités les plus importantes d'AJDT est un outil pour la visualisation des problèmes transversaux, ce qui est utile pour déboguer une spécification de coupe ponctuelle. Nous pouvons visualiser l'effet combiné avant même que le code ne soit déployé.

Nous utilisons le plugin AspectJ Maven de Mojo pour intégrer des aspects AspectJ dans nos classes en utilisant le compilateur AspectJ.

 org.codehaus.mojo aspectj-maven-plugin 1.7  1.8 1.8 1.8 true true ignore UTF-8       compile  test-compile    

Pour plus de détails sur la référence des options du compilateur AspectJ, nous pouvons consulter le lien suivant.

Ajoutons quelques cas de test pour notre classe Account:

public class AccountTest { private Account account; @Before public void before() { account = new Account(); } @Test public void given20AndMin10_whenWithdraw5_thenSuccess() { assertTrue(account.withdraw(5)); } @Test public void given20AndMin10_whenWithdraw100_thenFail() { assertFalse(account.withdraw(100)); } }

Lorsque nous exécutons les cas de test, le texte ci-dessous qui est affiché dans la console signifie que nous avons tissé avec succès le code source:

[INFO] Join point 'method-call (boolean com.baeldung.aspectj.Account.withdraw(int))' in Type 'com.baeldung.aspectj.test.AccountTest' (AccountTest.java:20) advised by around advice from 'com.baeldung.aspectj.AccountAspect' (AccountAspect.class:18(from AccountAspect.aj)) [INFO] Join point 'method-call (boolean com.baeldung.aspectj.Account.withdraw(int))' in Type 'com.baeldung.aspectj.test.AccountTest' (AccountTest.java:20) advised by before advice from 'com.baeldung.aspectj.AccountAspect' (AccountAspect.class:13(from AccountAspect.aj)) [INFO] Join point 'method-call (boolean com.baeldung.aspectj.Account.withdraw(int))' in Type 'com.baeldung.aspectj.test.AccountTest' (AccountTest.java:20) advised by after advice from 'com.baeldung.aspectj.AccountAspect' (AccountAspect.class:26(from AccountAspect.aj)) 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Balance before withdrawal: 20 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Withdraw ammout: 5 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Balance after withdrawal : 15 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Balance before withdrawal: 20 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Withdraw ammout: 100 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Withdrawal Rejected! 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Balance after withdrawal : 20

6. Tissage post-compilation

Le tissage post-compilation (parfois également appelé tissage binaire) est utilisé pour tisser des fichiers de classe et des fichiers JAR existants. Comme pour le tissage au moment de la compilation, les aspects utilisés pour le tissage peuvent être sous forme source ou binaire, et peuvent eux-mêmes être tissés par aspects.

Pour ce faire avec le plug-in AspectJ Maven de Mojo, nous devons configurer tous les fichiers JAR que nous aimerions tisser dans la configuration du plug-in:

   org.agroup to-weave   org.anothergroup gen   

Les fichiers JAR contenant les classes à tisser doivent être répertoriés comme dans le projet Maven et listés comme dans le plugin AspectJ Maven.

7. Tissage à la charge

Le tissage au moment du chargement est simplement un tissage binaire différé jusqu'au moment où un chargeur de classe charge un fichier de classe et définit la classe dans la JVM.

Pour soutenir cela, un ou plusieurs «chargeurs de classe de tissage» sont nécessaires. Ceux-ci sont soit fournis explicitement par l'environnement d'exécution, soit activés à l'aide d'un «agent de tissage».

7.1. Activation du tissage au moment du chargement

AspectJ load-time weaving can be enabled using AspectJ agent that can get involved in the class loading process and weave any types before they are defined in the VM. We specify the javaagent option to the JVM -javaagent:pathto/aspectjweaver.jar or using Maven plugin to configure the javaagent :

 org.apache.maven.plugins maven-surefire-plugin 2.10   -javaagent:"${settings.localRepository}"/org/aspectj/ aspectjweaver/${aspectj.version}/ aspectjweaver-${aspectj.version}.jar  true always  

7.2. Configuration Weaver

AspectJ's load-time weaving agent is configured by the use of aop.xml files. It looks for one or more aop.xml files on the classpath in the META-INF directory and aggregates the contents to determine the weaver configuration.

An aop.xml file contains two key sections:

  • Aspects: defines one or more aspects to the weaver and controls which aspects are to be used in the weaving process. The aspects element may optionally contain one or more include and exclude elements (by default, all defined aspects are used for weaving)
  • Weaver: defines weaver options to the weaver and specifies the set of types that should be woven. If no include elements are specified then all types visible to the weaver will be woven

Let's configure an aspect to the weaver:

As we can see, we have configured an aspect that points to the AccountAspect, and only the source code in the com.baeldung.aspectj package will be woven by AspectJ.

8. Annotating Aspects

In addition to the familiar AspectJ code-based style of aspect declaration, AspectJ 5 also supports an annotation-based style of aspect declaration. We informally call the set of annotations that support this development style the “@AspectJ” annotations.

Let's create an annotation:

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Secured { public boolean isLocked() default false; }

We use the @Secured annotation to enable or disable a method:

public class SecuredMethod { @Secured(isLocked = true) public void lockedMethod() { } @Secured(isLocked = false) public void unlockedMethod() { } }

Next, we add an aspect using AspectJ annotation-style, and check the permission based on the attribute of the @Secured annotation:

@Aspect public class SecuredMethodAspect { @Pointcut("@annotation(secured)") public void callAt(Secured secured) { } @Around("callAt(secured)") public Object around(ProceedingJoinPoint pjp, Secured secured) throws Throwable { return secured.isLocked() ? null : pjp.proceed(); } }

For more detail on AspectJ annotation-style, we can check out the following link.

Next, we weave our class and aspect using load-time weaver and put aop.xml under META-INF folder:

Finally, we add unit test and check the result:

@Test public void testMethod() throws Exception { SecuredMethod service = new SecuredMethod(); service.unlockedMethod(); service.lockedMethod(); }

Lorsque nous exécutons les cas de test, nous pouvons vérifier la sortie de la console pour vérifier que nous avons réussi à tisser notre aspect et notre classe dans le code source:

[INFO] Join point 'method-call (void com.baeldung.aspectj.SecuredMethod.unlockedMethod())' in Type 'com.baeldung.aspectj.test.SecuredMethodTest' (SecuredMethodTest.java:11) advised by around advice from 'com.baeldung.aspectj.SecuredMethodAspect' (SecuredMethodAspect.class(from SecuredMethodAspect.java)) 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.SecuredMethod - unlockedMethod 2016-11-15 22:53:51 [main] INFO c.b.aspectj.SecuredMethodAspect - public void com.baeldung.aspectj.SecuredMethod.lockedMethod() is locked

9. Conclusion

Dans cet article, nous avons couvert les concepts introductifs d'AspectJ. Pour plus de détails, vous pouvez consulter la page d'accueil d'AspectJ.

Vous pouvez trouver le code source de cet article sur GitHub.