Inleiding tot AspectJ

1. Inleiding

Dit artikel is een snelle en praktische inleiding tot AspectJ.

Eerst laten we zien hoe aspectgeoriënteerd programmeren mogelijk is, en daarna zullen we ons concentreren op het verschil tussen compileren, postcompileren en weven tijdens het laden.

Laten we beginnen met een korte introductie van aspectgeoriënteerd programmeren (AOP) en de basisprincipes van AspectJ.

2. Overzicht

AOP is een programmeerparadigma dat tot doel heeft de modulariteit te vergroten door de scheiding van transversale problemen mogelijk te maken. Het doet dit door extra gedrag toe te voegen aan bestaande code zonder de code zelf te wijzigen. In plaats daarvan geven we afzonderlijk aan welke code moet worden gewijzigd.

AspectJ implementeert zowel zorgen als het verweven van transversale problemen met behulp van uitbreidingen van de programmeertaal Java.

3. Maven afhankelijkheden

AspectJ biedt verschillende bibliotheken aan, afhankelijk van het gebruik ervan. We kunnen Maven-afhankelijkheden vinden onder group org.aspectj in de Maven Central-repository.

In dit artikel concentreren we ons op de afhankelijkheden die nodig zijn om aspecten en Weaver te maken met behulp van de compilatietijd, postcompilatie en laadtijd Weavers.

3.1. AspectJ-runtime

Wanneer een AspectJ-programma wordt uitgevoerd, moet het klassenpad de klassen en aspecten bevatten, samen met de AspectJ-runtimebibliotheek aspectjrt.jar:

 org.aspectj aspectjrt 1.8.9 

Deze afhankelijkheid is beschikbaar via Maven Central.

3.2. AspectJWeaver

Naast de AspectJ-runtime-afhankelijkheid, moeten we ook de aspectjweaver.jar om advies te geven aan de Java-klasse tijdens het laden:

 org.aspectj aspectjweaver 1.8.9 

De afhankelijkheid is ook beschikbaar op Maven Central.

4. Aspect Creatie

AspectJ zorgt voor een implementatie van AOP en heeft drie kernbegrippen:

  • Word lid van Point
  • Pointcut
  • Advies

We demonstreren deze concepten door een eenvoudig programma te maken om het saldo van een gebruikersaccount te valideren.

Laten we eerst een Account klasse met een bepaald saldo en een methode om terug te trekken:

openbare klasse Account {int saldo = 20; openbare boolean opname (int bedrag) {if (saldo <bedrag) {return false; } saldo = saldo - bedrag; terugkeer waar; }}

We maken een AccountAspect.aj bestand om rekeninginformatie te loggen en om het rekeningsaldo te valideren (merk op dat AspectJ-bestanden eindigen met een ".aj" bestandsextensie):

openbaar aspect AccountAspect {final int MIN_BALANCE = 10; pointcut callWithDraw (int bedrag, Account acc): call (boolean Account.withdraw (int)) && args (bedrag) && target (acc); before (int bedrag, rekening acc): callWithDraw (bedrag, acc) {} boolean rond (int bedrag, rekening acc): callWithDraw (bedrag, acc) {if (acc.balans <bedrag) {return false; } terug te gaan (bedrag, acc); } after (int bedrag, rekeningsaldo): callWithDraw (bedrag, saldo) {}}

Zoals we kunnen zien, hebben we een pointcut naar de opnamemethode en creëerde drie adviseert die verwijzen naar de gedefinieerde pointcut.

Om het volgende te begrijpen, introduceren we de volgende definities:

  • Aspect: Een modularisering van een zorg die meerdere objecten beslaat. Elk aspect focust op een specifieke transversale functionaliteit
  • Sluit je aan bij punt: Een punt tijdens de uitvoering van een script, zoals de uitvoering van een methode of eigenschapstoegang
  • Advies: Actie ondernomen door een aspect op een bepaald verbindingspunt
  • Pointcut: Een reguliere expressie die overeenkomt met join-punten. Een advies is gekoppeld aan een pointcut-uitdrukking en wordt uitgevoerd op elk verbindingspunt dat overeenkomt met de pointcut

Voor meer details over deze concepten en hun specifieke semantiek, kunnen we de volgende link raadplegen.

Vervolgens moeten we de aspecten in onze code verweven. In de onderstaande secties worden drie verschillende soorten weven behandeld: weven tijdens het compileren, weven na het compileren en weven in de laadtijd in AspectJ.

5. Compile-Time Weaving

De eenvoudigste benadering van weven is weven tijdens het compileren. Als we zowel de broncode van het aspect hebben als de code waarin we aspecten gebruiken, zal de AspectJ-compiler vanaf de bron compileren en een geweven klassebestand als uitvoer produceren. Daarna, bij uitvoering van uw code, wordt de uitvoerklasse van het weefproces in JVM geladen als een normale Java-klasse.

We kunnen de AspectJ Development Tools downloaden omdat deze een gebundelde AspectJ-compiler bevat. Een van de belangrijkste functies van AJDT is een tool voor het visualiseren van transversale problemen, wat handig is voor het debuggen van een pointcut-specificatie. We kunnen het gecombineerde effect visualiseren, zelfs voordat de code is geïmplementeerd.

We gebruiken Mojo's AspectJ Maven-plug-in om AspectJ-aspecten in onze klassen te weven met behulp van de AspectJ-compiler.

 org.codehaus.mojo aspectj-maven-plugin 1.7 1.8 1.8 1.8 true true negeren UTF-8 compileren test-compileren 

Voor meer details over optiereferentie van de AspectJ-compiler, willen we misschien de volgende link bekijken.

Laten we enkele testcases toevoegen voor onze accountklasse:

openbare klasse AccountTest {privéaccountaccount; @Before public void before () {account = new Account (); } @Test openbare leegte gegeven20AndMin10_whenWithdraw5_thenSuccess () {assertTrue (account.withdraw (5)); } @Test openbare ongeldig gegeven20AndMin10_whenWithdraw100_thenFail () {assertFalse (account.withdraw (100)); }}

Wanneer we de testcases uitvoeren, betekent de onderstaande tekst die in de console wordt weergegeven dat we de broncode met succes hebben geweven:

[INFO] Join point 'method-call (boolean com.baeldung.aspectj.Account.withdraw (int))' in Type 'com.baeldung.aspectj.test.AccountTest' (AccountTest.java:20) geadviseerd door ongeveer advies van 'com.baeldung.aspectj.AccountAspect' (AccountAspect.class: 18 (van AccountAspect.aj)) [INFO] Join point 'method-call (boolean com.baeldung.aspectj.Account.withdraw (int))' in Type ' com.baeldung.aspectj.test.AccountTest '(AccountTest.java:20) geadviseerd door voorafgaand advies van' com.baeldung.aspectj.AccountAspect '(AccountAspect.class: 13 (van AccountAspect.aj)) [INFO] Join point' method-call (boolean com.baeldung.aspectj.Account.withdraw (int)) 'in Type' com.baeldung.aspectj.test.AccountTest '(AccountTest.java:20) geadviseerd door na advies van' com.baeldung.aspectj .AccountAspect '(AccountAspect.class: 26 (from AccountAspect.aj)) 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Saldo vóór opname: 20 2016-11-15 22: 53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Ammout opnemen: 5 2016 -11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Saldo na opname: 15 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Saldo vóór opname: 20 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Opname ammout: 100 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Intrekking afgewezen! 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Saldo na opname: 20

6. Post-compile weven

Post-compileren weven (ook wel binair weven genoemd) wordt gebruikt om bestaande klassenbestanden en JAR-bestanden te weven. Net als bij het weven tijdens het compileren, kunnen de aspecten die voor het weven worden gebruikt in bron- of binaire vorm zijn, en kunnen ze zelf door aspecten geweven zijn.

Om dit te doen met Mojo's AspectJ Maven-plug-in, moeten we alle JAR-bestanden instellen die we in de plug-in-configuratie willen weven:

   org.agroup to-weave org.anothergroup gen 

De JAR-bestanden met de te weven klassen moeten worden vermeld als in het Maven-project en vermeld als in de van de AspectJ Maven-plug-in.

7. Weven tijdens het laden

Load-time weaving is simpelweg binair weven, uitgesteld tot het punt dat een class-loader een class-bestand laadt en de class definieert in de JVM.

Om dit te ondersteunen zijn een of meer “weefklasse laders” nodig. Deze worden ofwel expliciet geleverd door de runtime-omgeving of worden mogelijk gemaakt met behulp van een "weefagent".

7.1. Weven tijdens het laden inschakelen

AspectJ load-time weaving kan worden ingeschakeld met behulp van AspectJ-agent die kan worden betrokken bij het klasselaadproces en elk type kan weven voordat ze in de VM worden gedefinieerd. We specificeren de javaagent optie voor de JVM -javaagent: pathto / aspectjweaver.jar of met behulp van de Maven-plug-in om het javaagent :

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

7.2. Configuratie Weaver

Het weefmiddel voor de laadtijd van AspectJ wordt geconfigureerd door het gebruik van aop.xml bestanden. Het zoekt een of meer aop.xml bestanden op het klassenpad in het META-INF directory en aggregeert de inhoud om de weaver-configuratie te bepalen.

Een aop.xml bestand bevat twee belangrijke secties:

  • Aspecten: definieert een of meer aspecten voor de wever en bepaalt welke aspecten gebruikt worden in het weefproces. De aspecten element kan optioneel een of meer bevatten omvatten en uitsluiten elementen (standaard worden alle gedefinieerde aspecten gebruikt voor het weven)
  • Wever: definieert de weveropties voor de wever en specificeert de reeks soorten die moeten worden geweven. Als er geen include-elementen zijn gespecificeerd, worden alle soorten die zichtbaar zijn voor de wever, geweven

Laten we een aspect voor de wever configureren:

Zoals we kunnen zien, hebben we een aspect geconfigureerd dat verwijst naar de Accountaspect, en alleen de broncode in het com.baeldung.aspectj pakket wordt geweven door AspectJ.

8. Aspecten annoteren

Naast de bekende op AspectJ-code gebaseerde stijl van aspectverklaring, ondersteunt AspectJ 5 ook een op annotatie gebaseerde stijl van aspectverklaring. We noemen de set annotaties die deze ontwikkelstijl ondersteunen informeel de '@AspectJ”Annotaties.

Laten we een annotatie maken:

@Retention (RetentionPolicy.RUNTIME) @Target (ElementType.METHOD) openbaar @interface Beveiligd {openbare boolean isLocked () standaard false; }

Wij gebruiken de @Beveiligd annotatie om een ​​methode in of uit te schakelen:

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

Vervolgens voegen we een aspect toe met behulp van AspectJ-annotatiestijl, en controleren we de toestemming op basis van het attribuut van de @Secured-annotatie:

@Aspect openbare klasse SecuredMethodAspect {@Pointcut ("@ annotatie (beveiligd)") openbare ongeldige callAt (beveiligd beveiligd) {} ​​@Around ("callAt (beveiligd)") openbaar object rond (ProceedingsJoinPoint pjp, beveiligd beveiligd) worpen Gooibaar {return secure.isLocked ()? null: pjp.proceed (); }}

Voor meer details over de annotatiestijl van AspectJ kunnen we de volgende link bekijken.

Vervolgens weven we onze klasse en aspect met behulp van load-time weaver en put aop.xml onder META-INF map:

Ten slotte voegen we een unit-test toe en controleren we het resultaat:

@Test public void testMethod () gooit uitzondering {SecuredMethod-service = nieuwe SecuredMethod (); service.unlockedMethod (); service.lockedMethod (); }

Wanneer we de testcases uitvoeren, kunnen we de console-uitvoer controleren om te verifiëren dat we met succes ons aspect en onze klasse in de broncode hebben geweven:

[INFO] Join-punt 'method-call (void com.baeldung.aspectj.SecuredMethod.unlockedMethod ())' in Typ 'com.baeldung.aspectj.test.SecuredMethodTest' (SecuredMethodTest.java:11) geadviseerd door ongeveer advies van ' 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 cbaspectj.SecuredMethodAspect - public void com.baeldung.aspectj.SecuredMethod.lockedMethod () is vergrendeld

9. Conclusie

In dit artikel hebben we inleidende concepten over AspectJ behandeld. Voor details kunt u een kijkje nemen op de AspectJ-startpagina.

Je kunt de broncode voor dit artikel vinden op GitHub.