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:

  1. Kompileringstidsvævning: AspectJ-compileren tager både input af kildekoden til vores aspekt og vores applikation og producerer en vævet klassefiler som output
  2. 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
  3. 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:

  1. 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
  2. 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:

JoinpointForår AOP understøttetAspectJ understøttet
MetodeopkaldIngenJa
MetodeudførelseJaJa
KonstruktøropkaldIngenJa
Udførelse af konstruktørIngenJa
Statisk initialisering af udførelseIngenJa
Initialisering af objektIngenJa
FeltreferenceIngenJa
FeltopgaveIngenJa
Handler udførelseIngenJa
Rådgivning udførelseIngenJa

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 AOPAspectJ
Implementeret i ren JavaImplementeret ved hjælp af udvidelser af Java programmeringssprog
Intet behov for separat kompileringsprocesBrug for AspectJ-compiler (ajc), medmindre LTW er konfigureret
Kun vævet runtime er tilgængeligtRuntime 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å metodeniveauMere kraftfuld - kan væve felter, metoder, konstruktører, statiske initialiserere, endelig klasse / metoder osv ...
Kan kun implementeres på bønner, der administreres af Spring containerKan implementeres på alle domæneobjekter
Understøtter kun pointcuts til metodeudførelseUnderstøtter alle genveje
Proxyer oprettes af målrettede objekter, og aspekter anvendes på disse fuldmagterAspekter flettes direkte i kode, før applikationen udføres (før runtime)
Meget langsommere end AspectJBedre ydeevne
Let at lære og anvendeForholdsvis 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.