Sammenligning av Spring AOP og AspectJ
1. Introduksjon
Det er flere tilgjengelige AOP-biblioteker i dag, og disse må kunne svare på en rekke spørsmål:
- Er den kompatibel med den eksisterende eller nye applikasjonen min?
- Hvor kan jeg implementere AOP?
- Hvor raskt integreres det med applikasjonen min?
- Hva er ytelsen overhead?
I denne artikkelen vil vi se på å svare på disse spørsmålene og introdusere Spring AOP og AspectJ - de to mest populære AOP-rammene for Java.
2. AOP-konsepter
Før vi begynner, la oss gjøre en rask, høyt nivå gjennomgang av vilkår og kjernekonsepter:
- Aspekt - en standard kode / funksjon som er spredt over flere steder i applikasjonen og vanligvis er forskjellig fra den faktiske forretningslogikken (for eksempel transaksjonsadministrasjon). Hvert aspekt fokuserer på en spesifikk tverrgående funksjonalitet
- Joinpoint - det er et bestemt punkt under gjennomføring av programmer som metodeutførelse, konstruktøranrop eller feltoppgave
- Råd - handlingen som er tatt av aspektet i et bestemt sammenføyningspunkt
- Pointcut - et vanlig uttrykk som samsvarer med et joinpoint. Hver gang et tilknytningspunkt samsvarer med et snarvei, utføres et spesifisert råd tilknyttet det snarveien
- Veving - prosessen med å knytte aspekter til målrettede objekter for å lage et anbefalt objekt
3. Spring AOP og AspectJ
La oss nå diskutere Spring AOP og AspectJ over en rekke akser - for eksempel evner, mål, veving, intern struktur, sammenføyningspunkter og enkelhet.
3.1. Evner og mål
Enkelt sagt, Spring AOP og AspectJ har forskjellige mål.
Spring AOP har som mål å gi en enkel AOP-implementering på tvers av Spring IoC for å løse de vanligste problemene som programmerere står overfor. Det er ikke ment som en komplett AOP-løsning - den kan bare brukes på bønner som administreres av en Spring container.
På den andre siden, AspectJ er den originale AOP-teknologien som tar sikte på å gi en komplett AOP-løsning. Det er mer robust, men også betydelig mer komplisert enn Spring AOP. Det er også verdt å merke seg at AspectJ kan brukes på alle domeneobjekter.
3.2. Veving
Både AspectJ og Spring AOP bruker forskjellige typer veving som påvirker deres atferd med hensyn til ytelse og brukervennlighet.
AspectJ bruker tre forskjellige typer veving:
- Veving av kompileringstid: AspectJ-kompilatoren tar både kildekoden til vårt aspekt og applikasjonen som input og produserer en vevd klassefiler som utdata
- Veving etter kompilering: Dette er også kjent som binær veving. Den brukes til å veve eksisterende klassefiler og JAR-filer med våre aspekter
- Veving i lastetid: Dette er akkurat som den tidligere binære vevingen, med en forskjell at vevingen utsettes til en klasselaster laster klassefilene til JVM
For mer inngående informasjon om AspectJ, gå videre til denne artikkelen.
Siden AspectJ bruker kompileringstid og veving av klasselastetid, Spring AOP bruker runtime veving.
Med runtime-veving veves aspektene under utførelsen av applikasjonen ved hjelp av proxyer for det målrettede objektet - ved hjelp av enten JDK dynamisk proxy eller CGLIB proxy (som blir diskutert i neste punkt):
3.3. Intern struktur og anvendelse
Spring AOP er et proxy-basert AOP-rammeverk. Dette betyr at for å implementere aspekter til målobjektene, vil det opprette fullmakter til det objektet. Dette oppnås på en av to måter:
- JDK dynamisk proxy - den foretrukne måten for Spring AOP. Når det målrettede objektet implementerer til og med ett grensesnitt, vil JDK dynamisk proxy brukes
- CGLIB-proxy - hvis målobjektet ikke implementerer et grensesnitt, kan CGLIB-proxy brukes
Vi kan lære mer om Spring AOP-proxy-mekanismer fra de offisielle dokumentene.
AspectJ, derimot, gjør ikke noe på kjøretid ettersom klassene er samlet direkte med aspekter.
Og i motsetning til Spring AOP, krever det ingen designmønstre. For å veve aspektene til koden, introduserer den kompilatoren kjent som AspectJ-kompilator (ajc), hvor vi kompilerer programmet vårt og kjører det ved å levere et lite (<100K) kjøretidsbibliotek.
3.4. Joinpoints
I avsnitt 3.3 viste vi at Spring AOP er basert på proxy-mønstre. På grunn av dette må den underklasse den målrettede Java-klassen og bruke tverrgående bekymringer tilsvarende.
Men det kommer med en begrensning. Vi kan ikke bruke tverrgående bekymringer (eller aspekter) på tvers av klasser som er "endelige" fordi de ikke kan overstyres, og det vil dermed føre til et unntak for kjøretid.
Det samme gjelder for statiske og endelige metoder. Våraspekter kan ikke brukes på dem fordi de ikke kan overstyres. Derfor spring AOP på grunn av disse begrensningene, støtter bare sammenkoblingspunkter for metodeutførelse.
Derimot, AspectJ vever de kryssende bekymringene direkte i den faktiske koden før kjøretid. I motsetning til Spring AOP, krever det ikke å underklasse det målrettede objektet og støtter dermed også mange andre tilknytningspunkter. Følgende er sammendraget av støttede tilknytningspunkter:
Joinpoint | Vår AOP-støttet | AspectJ støttes |
---|---|---|
Metodeanrop | Nei | Ja |
Metodeutførelse | Ja | Ja |
Konstruktøranrop | Nei | Ja |
Konstruktørutførelse | Nei | Ja |
Statisk initialisering av utførelse | Nei | Ja |
Initialisering av objekt | Nei | Ja |
Feltreferanse | Nei | Ja |
Feltoppgave | Nei | Ja |
Utførelse av behandler | Nei | Ja |
Rådgjennomføring | Nei | Ja |
Det er også verdt å merke seg at i vår AOP blir ikke aspekter brukt på metoden som kalles i samme klasse.
Det er åpenbart fordi når vi kaller en metode innen samme klasse, så kaller vi ikke metoden for proxyen som Spring AOP leverer. Hvis vi trenger denne funksjonaliteten, må vi definere en egen metode i forskjellige bønner, eller bruke AspectJ.
3.5. Enkelhet
Spring AOP er åpenbart enklere fordi den ikke introduserer noen ekstra kompilator eller vever mellom byggeprosessen vår. Den bruker runtime-veving, og integreres derfor sømløst med vår vanlige byggeprosess. Selv om det ser enkelt ut, fungerer det bare med bønner som administreres av Spring.
For å bruke AspectJ må vi imidlertid introdusere AspectJ-kompilatoren (ajc) og pakke alle bibliotekene våre på nytt (med mindre vi bytter til veving etter kompilering eller lastetid).
Dette er selvfølgelig mer komplisert enn førstnevnte - fordi det introduserer AspectJ Java Tools (som inkluderer en kompilator (ajc), en feilsøking (ajdb), en dokumentasjonsgenerator (ajdoc), en programstruktur nettleser (ajbrowser)) som vi trenger å integrere med enten vår IDE eller byggeverktøyet.
3.6. Opptreden
Når det gjelder ytelse, veving av kompilering er mye raskere enn veving i kjøretid. Spring AOP er et proxybasert rammeverk, så det opprettes fullmakter på tidspunktet for oppstart av applikasjonen. Det er også noen flere metodeinnkallelser per aspekt, noe som påvirker ytelsen negativt.
På den annen side fletter AspectJ aspektene inn i hovedkoden før applikasjonen kjøres, og det er dermed ingen ekstra kjøretidskostnader, i motsetning til Spring AOP.
Av disse grunner antyder referanseverdiene at AspectJ er nesten rundt 8 til 35 ganger raskere enn AOP for våren.
4. Oppsummering
Denne raske tabellen oppsummerer nøkkelforskjellene mellom Spring AOP og AspectJ:
Vår AOP | AspectJ |
---|---|
Implementert i ren Java | Implementert ved hjelp av utvidelser av Java programmeringsspråk |
Ingen behov for egen kompileringsprosess | Trenger AspectJ-kompilator (ajc) med mindre LTW er konfigurert |
Bare kjøretid veving er tilgjengelig | Runtime-veving er ikke tilgjengelig. Støtter veving av kompileringstid, etterkompilering og lastetid |
Mindre kraftig - støtter bare veving på metodenivå | Mer kraftfull - kan veve felt, metoder, konstruktører, statiske initialiserere, endelig klasse / metoder, etc ... |
Kan bare implementeres på bønner som administreres av Spring container | Kan implementeres på alle domeneobjekter |
Støtter bare snarveier for metodeutførelse | Støtt alle punktkutt |
Fullmakter opprettes av målrettede objekter, og aspekter brukes på disse fullmaktene | Aspekter veves direkte inn i koden før applikasjonen kjøres (før kjøretid) |
Mye tregere enn AspectJ | Bedre ytelse |
Lett å lære og bruke | Forholdsvis mer komplisert enn Spring AOP |
5. Velge riktig ramme
Hvis vi analyserer alle argumentene i denne delen, begynner vi å forstå at det ikke er det ene rammeverket som er bedre enn et annet.
Enkelt sagt, valget avhenger sterkt av våre krav:
- Rammeverk: Hvis applikasjonen ikke bruker Spring framework, har vi ikke annet valg enn å slippe ideen om å bruke Spring AOP fordi den ikke klarer noe som er utenfor rekkevidden til vårcontaineren. Imidlertid, hvis applikasjonen vår er opprettet helt ved hjelp av Spring framework, kan vi bruke Spring AOP ettersom det er greit å lære og bruke
- Fleksibilitet: Gitt begrenset støttepunkt for sammenkobling, er Spring AOP ikke en komplett AOP-løsning, men den løser de vanligste problemene som programmerere står overfor. Selv om vi ønsker å grave dypere og utnytte AOP til den maksimale muligheten og vil ha støtte fra et bredt utvalg av tilgjengelige tilknytningspunkter, er AspectJ valget
- Ytelse: Hvis vi bruker begrensede aspekter, er det trivielle ytelsesforskjeller. Men det er noen ganger tilfeller når en applikasjon har mer enn titusenvis av aspekter. Vi ønsker ikke å bruke runtime-veving i slike tilfeller, så det ville være bedre å velge AspectJ. AspectJ er kjent for å være 8 til 35 ganger raskere enn Spring AOP
- Best of Both: Begge disse rammene er fullt kompatible med hverandre. Vi kan alltid dra nytte av Spring AOP når det er mulig, og fortsatt bruke AspectJ for å få støtte for sammenkoblingspunkter som ikke støttes av tidligere
6. Konklusjon
I denne artikkelen analyserte vi både Spring AOP og AspectJ, på flere viktige områder.
Vi sammenlignet de to tilnærmingene til AOP, både når det gjelder fleksibilitet og hvor lett de passer med applikasjonen vår.