Vergelijking van Spring AOP en AspectJ

1. Inleiding

Er zijn tegenwoordig meerdere AOP-bibliotheken beschikbaar en deze moeten een aantal vragen kunnen beantwoorden:

  • Is het compatibel met mijn bestaande of nieuwe applicatie?
  • Waar kan ik AOP implementeren?
  • Hoe snel integreert het met mijn applicatie?
  • Wat is de prestatieoverhead?

In dit artikel kijken we naar het beantwoorden van deze vragen en introduceren we Spring AOP en AspectJ - de twee meest populaire AOP-frameworks voor Java.

2. AOP-concepten

Laten we, voordat we beginnen, de termen en kernconcepten snel op hoog niveau beoordelen:

  • Aspect - een standaardcode / functie die over meerdere plaatsen in de applicatie is verspreid en doorgaans verschilt van de werkelijke bedrijfslogica (bijvoorbeeld transactiebeheer). Elk aspect focust op een specifieke transversale functionaliteit
  • Joinpoint - het is een bepaald punt tijdens de uitvoering van programma's zoals het uitvoeren van een methode, constructoroproep of veldtoewijzing
  • Advies - de actie die wordt ondernomen door het aspect in een specifiek joinpoint
  • Pointcut - een reguliere expressie die overeenkomt met een joinpoint. Elke keer dat een verbindingspunt overeenkomt met een pointcut, wordt een gespecificeerd advies behorend bij die pointcut uitgevoerd
  • Weven - het proces van het verbinden van aspecten met gerichte objecten om een ​​geadviseerd object te creëren

3. Spring AOP en AspectJ

Laten we nu Spring AOP en AspectJ bespreken over een aantal assen - zoals capaciteiten, doelen, weven, interne structuur, verbindingspunten en eenvoud.

3.1. Mogelijkheden en doelen

Simpel gezegd, Spring AOP en AspectJ hebben verschillende doelen.

Spring AOP heeft tot doel een eenvoudige AOP-implementatie te bieden in Spring IoC om de meest voorkomende problemen op te lossen waarmee programmeurs worden geconfronteerd. Het is niet bedoeld als een complete AOP-oplossing - het kan alleen worden toegepast op bonen die worden beheerd door een Spring-container.

Aan de andere kant, AspectJ is de originele AOP-technologie die tot doel heeft een complete AOP-oplossing te bieden. Het is robuuster maar ook aanzienlijk gecompliceerder dan Spring AOP. Het is ook vermeldenswaard dat AspectJ op alle domeinobjecten kan worden toegepast.

3.2. Weven

Zowel AspectJ als Spring AOP maakt gebruik van de verschillende soorten weefsels die hun gedrag ten aanzien van prestaties en gebruiksgemak beïnvloeden.

AspectJ maakt gebruik van drie verschillende soorten weefsels:

  1. Compile-time weven: De AspectJ-compiler neemt zowel de broncode van ons aspect als onze applicatie als invoer en produceert een geweven klasse-bestanden als uitvoer
  2. Weven na het compileren: Dit wordt ook wel binair weven genoemd. Het wordt gebruikt om bestaande klassenbestanden en JAR-bestanden met onze aspecten te verweven
  3. Load-time weven: Dit is precies hetzelfde als het vroegere binaire weven, met een verschil dat het weven wordt uitgesteld totdat een klassenlader de klassenbestanden laadt naar de JVM

Ga voor meer diepgaande informatie over AspectJ zelf naar dit artikel.

Aangezien AspectJ compilatietijd en classloadtijdweven gebruikt, Spring AOP maakt gebruik van runtime weaving.

Bij runtime weaving worden de aspecten geweven tijdens de uitvoering van de applicatie met behulp van proxy's van het beoogde object - met behulp van ofwel JDK dynamische proxy of CGLIB proxy (die in het volgende punt worden besproken):

3.3. Interne structuur en toepassing

Spring AOP is een op proxy gebaseerd AOP-framework. Dit betekent dat om aspecten aan de doelobjecten te implementeren, het proxy's van dat object zal creëren. Dit kan op twee manieren worden bereikt:

  1. JDK dynamische proxy - de voorkeursmanier voor Spring AOP. Telkens wanneer het beoogde object ook maar één interface implementeert, wordt de dynamische JDK-proxy gebruikt
  2. CGLIB-proxy - als het doelobject geen interface implementeert, kan CGLIB-proxy worden gebruikt

We kunnen meer te weten komen over Spring AOP-proxy-mechanismen in de officiële documenten.

AspectJ, aan de andere kant, doet niets tijdens runtime, aangezien de klassen rechtstreeks met aspecten worden gecompileerd.

En dus in tegenstelling tot Spring AOP, heeft het geen ontwerppatronen nodig. Om de aspecten aan de code te weven, introduceert het zijn compiler die bekend staat als AspectJ-compiler (ajc), waarmee we ons programma compileren en het vervolgens uitvoeren door een kleine (<100K) runtime-bibliotheek te leveren.

3.4. Joinpoints

In paragraaf 3.3 hebben we laten zien dat Spring AOP is gebaseerd op proxypatronen. Daarom moet het de beoogde Java-klasse onderklassen en dienovereenkomstig transversale zorgen toepassen.

Maar het heeft een beperking. We kunnen geen transversale zorgen (of aspecten) toepassen op klassen die "definitief" zijn, omdat ze niet kunnen worden overschreven en dit zou resulteren in een runtime-uitzondering.

Hetzelfde geldt voor statische en definitieve methoden. Veeraspecten kunnen er niet op worden toegepast omdat ze niet kunnen worden opgeheven. Daarom ondersteunt Spring AOP, vanwege deze beperkingen, alleen join-punten voor het uitvoeren van methoden.

Echter, AspectJ verweeft de transversale problemen direct in de daadwerkelijke code vóór runtime. In tegenstelling tot Spring AOP, is het niet nodig om het beoogde object in een subklasse te plaatsen en ondersteunt het dus ook vele andere joinpoints. Hieronder volgt de samenvatting van ondersteunde joinpoints:

JoinpointSpring AOP ondersteundAspectJ ondersteund
Methode OproepNeeJa
Methode-uitvoeringJaJa
Constructor-oproepNeeJa
Constructor uitvoeringNeeJa
Uitvoering van statische initialisatieNeeJa
Object initialisatieNeeJa
VeldreferentieNeeJa
VeldtoewijzingNeeJa
Handler uitvoeringNeeJa
Advies uitvoeringNeeJa

Het is ook vermeldenswaard dat in Spring AOP aspecten niet worden toegepast op de methode die binnen dezelfde klasse wordt aangeroepen.

Dat is duidelijk omdat wanneer we een methode binnen dezelfde klasse aanroepen, we niet de methode van de proxy aanroepen die Spring AOP levert. Als we deze functionaliteit nodig hebben, dan moeten we een aparte methode in verschillende bonen definiëren, of AspectJ gebruiken.

3.5. Eenvoud

Spring AOP is duidelijk eenvoudiger omdat het geen extra compiler of wever introduceert tussen ons bouwproces. Het maakt gebruik van runtime-weefsels en integreert daarom naadloos met ons gebruikelijke bouwproces. Hoewel het er simpel uitziet, werkt het alleen met bonen die door Spring worden beheerd.

Om AspectJ te gebruiken, moeten we echter de AspectJ-compiler (ajc) introduceren en al onze bibliotheken opnieuw verpakken (tenzij we overschakelen naar post-compileren of load-time weaving).

Dit is natuurlijk ingewikkelder dan het eerste - omdat het AspectJ Java Tools introduceert (waaronder een compiler (ajc), een debugger (ajdb), een documentatiegenerator (ajdoc), een programmastructuurbrowser (ajbrowser)) die we moeten worden geïntegreerd met onze IDE of de build-tool.

3.6. Prestatie

Wat de prestaties betreft, compileren weven is veel sneller dan runtime weven. Spring AOP is een op proxy gebaseerd raamwerk, dus er is het creëren van proxy's op het moment dat de applicatie opstart. Er zijn ook nog een paar methode-aanroepen per aspect, wat de prestaties negatief beïnvloedt.

Aan de andere kant verweeft AspectJ de aspecten in de hoofdcode voordat de applicatie wordt uitgevoerd en is er dus geen extra runtime-overhead, in tegenstelling tot Spring AOP.

Om deze redenen suggereren de benchmarks dat AspectJ bijna 8 tot 35 keer sneller is dan Spring AOP.

4. Samenvatting

Deze korte tabel vat de belangrijkste verschillen tussen Spring AOP en AspectJ samen:

Lente AOPAspectJ
Geïmplementeerd in pure JavaGeïmplementeerd met behulp van uitbreidingen van de programmeertaal Java
Geen apart compilatieproces nodigVereist AspectJ-compiler (ajc) tenzij LTW is ingesteld
Alleen runtime-weven is beschikbaarRuntime-weven is niet beschikbaar. Ondersteunt compile-time, post-compile en load-time Weaving
Minder krachtig - ondersteunt alleen weven op methodniveauKrachtiger - kan velden, methoden, constructeurs, statische initialisatieprogramma's, laatste klassen / methoden, enz.Weven
Kan alleen worden geïmplementeerd op bonen die worden beheerd door Spring-containerKan op alle domeinobjecten worden geïmplementeerd
Ondersteunt alleen pointcuts voor het uitvoeren van methodenSteun alle pointcuts
Proxy's worden gemaakt van gerichte objecten en aspecten worden op deze proxy's toegepastAspecten worden direct in code verweven voordat de toepassing wordt uitgevoerd (vóór runtime)
Veel langzamer dan AspectJBetere prestatie
Gemakkelijk te leren en toe te passenRelatief ingewikkelder dan Spring AOP

5. Het juiste raamwerk kiezen

Als we alle argumenten in deze sectie analyseren, zullen we beginnen te begrijpen dat het helemaal niet zo is dat het ene raamwerk beter is dan het andere.

Simpel gezegd, de keuze hangt sterk af van onze vereisten:

  • Framework: als de applicatie geen Spring Framework gebruikt, hebben we geen andere keus dan het idee om Spring AOP te gebruiken laten vallen, omdat het niets kan beheren dat buiten het bereik van Spring Container valt. Als onze applicatie echter volledig met Spring-framework is gemaakt, kunnen we Spring AOP gebruiken, omdat het eenvoudig is om te leren en toe te passen
  • Flexibiliteit: Gezien de beperkte ondersteuning voor joinpoint, is Spring AOP geen complete AOP-oplossing, maar lost het de meest voorkomende problemen op waarmee programmeurs te maken hebben. Hoewel als we dieper willen graven en AOP maximaal willen benutten en de ondersteuning willen van een breed scala aan beschikbare joinpoints, dan is AspectJ de keuze
  • Prestaties: als we beperkte aspecten gebruiken, zijn er triviale prestatieverschillen. Maar er zijn soms gevallen waarin een applicatie meer dan tienduizenden aspecten heeft. We zouden in dergelijke gevallen geen gebruik willen maken van runtime weaving, dus het is beter om voor AspectJ te kiezen. Het is bekend dat AspectJ 8 tot 35 keer sneller is dan Spring AOP
  • Het beste van beide: beide frameworks zijn volledig compatibel met elkaar. We kunnen waar mogelijk altijd profiteren van Spring AOP en toch AspectJ gebruiken om ondersteuning te krijgen voor joinpoints die niet worden ondersteund door de eerste

6. Conclusie

In dit artikel hebben we zowel Spring AOP als AspectJ op verschillende belangrijke gebieden geanalyseerd.

We hebben de twee benaderingen van AOP vergeleken, zowel wat betreft flexibiliteit als hoe gemakkelijk ze in onze applicatie passen.