Sammenligning af Spring AOP og AspectJ
1. Introduktion
Der er flere tilgængelige AOP-biblioteker i dag, og disse skal være i stand til at besvare en række spørgsmål:
- Er det kompatibelt med min eksisterende eller nye applikation?
- Hvor kan jeg implementere AOP?
- Hvor hurtigt integreres det med min ansøgning?
- Hvad er performance overhead?
I denne artikel vil vi se på at besvare disse spørgsmål og introducere Spring AOP og AspectJ - de to mest populære AOP-rammer til Java.
2. AOP-koncepter
Før vi begynder, lad os lave en hurtig gennemgang på højt niveau af vilkår og kernekoncepter:
- Aspekt - en standardkode / funktion, der er spredt over flere steder i applikationen og typisk er forskellig fra den faktiske forretningslogik (for eksempel transaktionsstyring). Hvert aspekt fokuserer på en specifik tværgående funktionalitet
- Joinpoint - det er et bestemt punkt under udførelse af programmer som metodeudførelse, konstruktøropkald eller feltopgave
- Rådgivning - den handling, der træffes af aspektet i et bestemt sammenføjningspunkt
- Pointcut - et regulært udtryk, der matcher et joinpoint. Hver gang et sammenkoblingspunkt matcher en genvej, udføres et specifikt råd, der er knyttet til denne genvej
- Vævning - processen med at forbinde aspekter med målrettede objekter for at skabe et anbefalet objekt
3. Spring AOP og AspectJ
Lad os nu diskutere Spring AOP og AspectJ på tværs af en række akser - såsom kapaciteter, mål, vævning, intern struktur, sammenføjningspunkter og enkelhed.
3.1. Evner og mål
Kort sagt, Spring AOP og AspectJ har forskellige mål.
Spring AOP sigter mod at give en simpel AOP-implementering på tværs af Spring IoC for at løse de mest almindelige problemer, som programmører står over for. Det er ikke beregnet som en komplet AOP-løsning - det kan kun anvendes på bønner, der administreres af en Spring-container.
På den anden side, AspectJ er den originale AOP-teknologi, der sigter mod at levere komplet AOP-løsning. Det er mere robust, men også betydeligt mere kompliceret end Spring AOP. Det er også værd at bemærke, at AspectJ kan anvendes på alle domæneobjekter.
3.2. Vævning
Både AspectJ og Spring AOP bruger forskellige typer vævning, som påvirker deres adfærd med hensyn til ydeevne og brugervenlighed.
AspectJ bruger tre forskellige typer vævning:
- Kompileringstidsvævning: AspectJ-compileren tager både input af kildekoden til vores aspekt og vores applikation og producerer en vævet klassefiler som output
- Vævning efter kompilering: Dette er også kendt som binær vævning. Det bruges til at væve eksisterende klassefiler og JAR-filer med vores aspekter
- Vejning i belastningstid: Dette er nøjagtigt som den tidligere binære vævning med en forskel, at vævning udsættes, indtil en klasselæsser indlæser klassefilerne til JVM
For mere detaljeret information om AspectJ selv, gå videre til denne artikel.
Da AspectJ bruger kompileringstid og klasselastningstid, Spring AOP gør brug af runtime vævning.
Med runtime-vævning væves aspekterne under udførelsen af applikationen ved hjælp af proxyer for det målrettede objekt - ved hjælp af enten JDK dynamisk proxy eller CGLIB-proxy (som diskuteres i næste punkt):

3.3. Intern struktur og anvendelse
Spring AOP er en proxybaseret AOP-ramme. Dette betyder, at for at implementere aspekter til målobjekterne opretter det proxyer for objektet. Dette opnås på en af to måder:
- JDK dynamisk proxy - den foretrukne måde til Spring AOP. Når det målrettede objekt implementerer endda en grænseflade, vil JDK dynamisk proxy blive brugt
- CGLIB-proxy - hvis målobjektet ikke implementerer en grænseflade, kan CGLIB-proxy bruges
Vi kan lære mere om Spring AOP proxy-mekanismer fra de officielle dokumenter.
AspectJ gør derimod ikke noget ved runtime, da klasserne er samlet direkte med aspekter.
Og i modsætning til Spring AOP kræver det ingen designmønstre. For at væve aspekterne til koden introducerer den sin kompilator kendt som AspectJ compiler (ajc), hvorigennem vi kompilerer vores program og derefter kører det ved at levere et lille (<100K) runtime-bibliotek.
3.4. Deltagepunkter
I afsnit 3.3 viste vi, at Spring AOP er baseret på proxy-mønstre. På grund af dette er det nødvendigt at underklasse den målrettede Java-klasse og anvende tværgående bekymringer i overensstemmelse hermed.
Men det kommer med en begrænsning. Vi kan ikke anvende tværgående bekymringer (eller aspekter) på tværs af klasser, der er "endelige", fordi de ikke kan tilsidesættes, og det vil derfor resultere i en undtagelse fra runtime.
Det samme gælder for statiske og endelige metoder. Forårsaspekter kan ikke anvendes på dem, fordi de ikke kan tilsidesættes. Derfor forår AOP på grund af disse begrænsninger understøtter kun sammenkoblingspunkter for metodeudførelse.
Imidlertid, AspectJ væver de tværgående bekymringer direkte i den faktiske kode inden runtime. I modsætning til Spring AOP kræver det ikke at underklasse det målrettede objekt og understøtter dermed også mange andre joinpoints. Følgende er resuméet af understøttede joinpoints:
Joinpoint | Forår AOP understøttet | AspectJ understøttet |
---|---|---|
Metodeopkald | Ingen | Ja |
Metodeudførelse | Ja | Ja |
Konstruktøropkald | Ingen | Ja |
Udførelse af konstruktør | Ingen | Ja |
Statisk initialisering af udførelse | Ingen | Ja |
Initialisering af objekt | Ingen | Ja |
Feltreference | Ingen | Ja |
Feltopgave | Ingen | Ja |
Handler udførelse | Ingen | Ja |
Rådgivning udførelse | Ingen | Ja |
Det er også værd at bemærke, at aspekter i Spring AOP ikke anvendes på den metode, der kaldes inden for samme klasse.
Det er tydeligvis fordi, når vi kalder en metode inden for samme klasse, så kalder vi ikke metoden til den proxy, som Spring AOP leverer. Hvis vi har brug for denne funktionalitet, er vi nødt til at definere en separat metode i forskellige bønner eller bruge AspectJ.
3.5. Enkelhed
Spring AOP er naturligvis enklere, fordi det ikke introducerer nogen ekstra kompilator eller væver mellem vores byggeproces. Det bruger runtime vævning, og derfor integreres det problemfrit med vores sædvanlige byggeproces. Selvom det ser simpelt ud, fungerer det kun med bønner, der administreres af Spring.
For at bruge AspectJ er vi dog forpligtet til at introducere AspectJ-compileren (ajc) og pakke alle vores biblioteker igen (medmindre vi skifter til vævning efter kompilering eller indlæsningstid).
Dette er selvfølgelig mere kompliceret end førstnævnte - fordi det introducerer AspectJ Java Tools (som inkluderer en kompilator (ajc), en debugger (ajdb), en dokumentationsgenerator (ajdoc), en programstrukturbrowser (ajbrowser)), som vi skal integreres med enten vores IDE eller build-værktøjet.
3.6. Ydeevne
For så vidt angår præstation, vævning af kompileringstid er meget hurtigere end runtime-vævning. Spring AOP er en proxybaseret ramme, så der er oprettelse af proxyer på tidspunktet for applikationsstart. Der er også et par flere metodeopkald pr. Aspekt, hvilket påvirker ydeevnen negativt.
På den anden side væver AspectJ aspekterne i hovedkoden, før applikationen udføres, og der er således ingen ekstra runtime-omkostninger i modsætning til Spring AOP.
Af disse grunde antyder benchmarks, at AspectJ er næsten omkring 8 til 35 gange hurtigere end Spring AOP.
4. Resume
Denne hurtige tabel opsummerer de vigtigste forskelle mellem Spring AOP og AspectJ:
Forår AOP | AspectJ |
---|---|
Implementeret i ren Java | Implementeret ved hjælp af udvidelser af Java programmeringssprog |
Intet behov for separat kompileringsproces | Brug for AspectJ-compiler (ajc), medmindre LTW er konfigureret |
Kun vævet runtime er tilgængeligt | Runtime vævning er ikke tilgængelig. Understøtter vævning af kompileringstid, post-kompilering og indlæsningstid |
Mindre kraftfuldt - understøtter kun vævning på metodeniveau | Mere kraftfuld - kan væve felter, metoder, konstruktører, statiske initialiserere, endelig klasse / metoder osv ... |
Kan kun implementeres på bønner, der administreres af Spring container | Kan implementeres på alle domæneobjekter |
Understøtter kun pointcuts til metodeudførelse | Understøtter alle genveje |
Proxyer oprettes af målrettede objekter, og aspekter anvendes på disse fuldmagter | Aspekter flettes direkte i kode, før applikationen udføres (før runtime) |
Meget langsommere end AspectJ | Bedre ydeevne |
Let at lære og anvende | Forholdsvis mere kompliceret end Spring AOP |
5. Valg af den rigtige ramme
Hvis vi analyserer alle argumenterne i dette afsnit, begynder vi at forstå, at det overhovedet ikke er, at en ramme er bedre end en anden.
Kort sagt afhænger valget stærkt af vores krav:
- Framework: Hvis applikationen ikke bruger Spring framework, har vi ingen anden mulighed end at droppe ideen om at bruge Spring AOP, fordi den ikke kan styre noget, der er uden for springcontainerens rækkevidde. Men hvis vores applikation er oprettet udelukkende ved hjælp af Spring Framework, kan vi bruge Spring AOP, da det er ligetil at lære og anvende
- Fleksibilitet: I betragtning af den begrænsede understøttelse af sammenføjningspunkter er Spring AOP ikke en komplet AOP-løsning, men den løser de mest almindelige problemer, som programmører står over for. Selvom vi ønsker at grave dybere og udnytte AOP til sin maksimale kapacitet og ønsker support fra en bred vifte af tilgængelige joinpoints, så er AspectJ valget
- Ydeevne: Hvis vi bruger begrænsede aspekter, så er der trivielle forskelle i ydelse. Men der er undertiden tilfælde, hvor en applikation har mere end titusinder af aspekter. Vi ønsker ikke at bruge runtime-vævning i sådanne tilfælde, så det ville være bedre at vælge AspectJ. AspectJ er kendt for at være 8 til 35 gange hurtigere end Spring AOP
- Bedst af begge dele: Begge disse rammer er fuldt kompatible med hinanden. Vi kan altid udnytte Spring AOP, når det er muligt, og stadig bruge AspectJ til at få support til sammenkoblingspunkter, der ikke understøttes af den tidligere
6. Konklusion
I denne artikel analyserede vi både Spring AOP og AspectJ inden for flere nøgleområder.
Vi sammenlignede de to tilgange til AOP både med hensyn til fleksibilitet såvel som hvor let de passer til vores applikation.