Annotaties en Aspect Georiënteerd Programmeren
In dit artikel wil ik een ontwikkelconcept introduceren dat een aantal traditionele programmeer problemen sneller en schoner oplost dan mogelijk is met traditionele technieken: Aspect geOriënteerd Programmeren (AOP) in combinatie met Java Annotaties.
Wat is AOP?
Het idee achter AOP is dat het ontwikkelaars in staat stelt zorgen die de hele applicatie doorsnijden (cross-cutting concerns) op te nemen in hun code. Een cross-cutting concern is een gedeeld gedrag of gedeelde informatie welke over de hele applicatie kan worden gebruikt.
Het meest gebruikte voorbeeld van AOP is het logging issue. Logging is een cross-cutting gedrag dat wordt gebruikt door veel verschillende onderdelen van een applicatie maar indringt in de business logica van veel classes.
Met behulp van AOP technieken kan logging worden geïmplementeerd als een aspect dat wordt toegepast op alle betrokken classes zonder invloed uit te oefenen op hun eigenlijke implementatie. Dit is mogelijk doordat de aspecten worden toegepast met behulp van regels, de zogenaamde pointcuts. Point-cuts worden parallel geëvalueerd aan de normale flow van uitvoering van de applicatie.
Het volgende voorbeeld is een simpel logging aspect, geschreven in AspectJ en Java.
public aspect LoggingAspect { pointcut logAnyMethodCall() : call(* MyClass.*(..)); before() : logAnyMethodCall() { System.out.println("I am invoked at '" + thisJoinPoint.getSourceLocation() + "'"); } }
Dit aspect logt de filenaam plus regelnummer van alle code die een method in de class MyClass aanroept. Toegegeven, dit is een zeer onvolledige implementatie maar het laat het belangrijkste voordeel van AOP duidelijk zien: de originele source code blijft ongewijzigd terwijl er wel logging op is toegepast.
Nadelen
Het hiervoor benoemde gedrag – het onafhankelijk evalueren van pointcuts – leidt helaas ook meteen tot het voornaamste nadeel van AOP: het is niet direct duidelijk voor een ontwikkelaar welke aspects worden toegepast op de code. Aangezien een ‘advice’ – de code die wordt uitgevoerd wanneer een pointcut getriggerd wordt – op elke plaats in de code verweven kan worden, is het gedrag van de applicatie daarmee zelfs voor de ontwikkelaar onvoorspelbaar, tenzij hij/zij de zelf de aspects toepast.
Het is duidelijk dat een applicatie waarin veel verschillende acpecten van verschillende ontwikkelaars zitten snel een onderhoudsnachtmerrie kan worden.
In het volgende hoofdstuk zullen we zien hoe annotations ons kunnen helpen om dit probleem op te lossen en onze applicaties met aspects te verbeteren.
Java annotaties
Overview
Annotaties maken het mogelijk om meta-informatie in je code toe te voegen. Meta-informatie is informatie die niet deel uitmaakt van de code maar nuttige informatie over de code toevoegt. Dit maakt het mogelijk voor de ontwikkelaar om zijn/haar code te markeren als bijvoorbeeld “performend�?, “langzaam�? of -iets nuttiger- “overridden�? of “deprecated�?.
Het is erg belangrijk te beseffen dat de implementatie van een methode irrelevant is voor de annotatie: het is zelfs valide om bijvoorbeeld een abstracte methode te annoteren. De methode zelf is – en moet dat ook niet zijn– onwetend of de annotatie is geëvalueerd op een bepaald punt.
Annotaties en aspects
Het combineren van aspects en annotaties leidt tot een krachtige combinatie voor het oplossen van cross-cutting problemen. Het basis idee is om methodes, classes of members te annoteren met meta-informatie en aspects deze informatie te laten evalueren. Alleen als een aspect een methode ziet met de juiste annotatie zal het aspect de methode uitbreiden met extra functies.
Aangezien de annotaties logisch zijn gescheiden van de code, zal de applicatie prima draaien zonder dat deze worden geëvalueerd. Het toevoegen van annotaties aan een applicatie heeft geen enkel effect op het compileren, deployen of de testprocedures!
Aan de andere kant, als we er wel voor kiezen om functionaliteit aan een applicatie toe te voegen door het toepassen van een aspect op geannoteerde code, zal dit niet als een complete verrassing komen voor de ontwikkelaar: hij/zij heeft de code immers zelf geannoteerd.
Het logging voorbeeld
Laten we nog eens kijken naar het bovenstaande logging voorbeeld, nu aangepast om annotaties te ondersteunen:
public aspect LoggingAspect { pointcut logAnyMethodCall() : call(@Logged * MyClass.*(..)); // <------ @Logged toegevoegd before() : logAnyMethodCall() { System.out.println("I am invoked at '" + thisJoinPoint.getSourceLocation() + "'"); } }
Zoals je kan zien is de code identiek aan het eerste voorbeeld, afgezien van de gemarkeerde aanpassing. Voor de duidelijkheid: dit aspect logt de bron locatie van alle code die een methode op de class MyClass aanroept, maar nu alleen als de code is geannoteerd met @Logged.
Onderstaand een voorbeeld implementatie van de Logged annotatie van het bovenstaande aspect.
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Logged { }
Deze implementatie garandeert dat alleen methodes geannoteerd kunnen worden met @Logged.
Conclusie
Zoals uitgelegd in het voorbeeld in bovenstaande paragraaf, kan het aspect op iedere Java applicatie worden toegepast, maar de pointcut wordt alleen geactiveerd als de code is geannoteerd met @Logged. In tegenstelling tot het normale aspect georiënteerde ontwikkelen moeten we hier wel de source code aanpassen om deze te laten werken met ons aspect.
Lijkt het er daarmee op dat aspects geen echt voordeel geven boven reguliere ontwikkel technieken?
Bedenk dat de toegevoegde meta informatie geen invloed heeft op het gedrag van de code. We kunnen zoveel annotaties toevoegen als we willen en de code blijft nog steeds compileren en werken als daarvoor.
Daarbij; een normaal ontwikkelproces zou hiermee net iets anders verlopen. De ontwikkelaar schrijft een methode die logica uitvoert die logging nodig heeft. Hij annoteert dan de methode met de @Logged annotatie. Het is dan irrelevant of hij al dan niet een logging aspect implementeert, of dat hij binnen de methode zelf een logging functie implementeert. Alles wat hij doet is het toevoegen van meta informatie aan de methode, daarmee aangevend dat er logging mee uitgevoerd kan worden.
Om dit concept beter te begrijpen gaan we in een volgend artikel kijken naar een meer geavanceerd voorbeeld.


