Implementere en tilpasset vår AOP-kommentar

1. Introduksjon

I denne artikkelen implementerer vi en tilpasset AOP-kommentar ved hjelp av AOP-støtten våren.

Først vil vi gi et høyt nivå oversikt over AOP, og forklare hva det er og fordelene. Etter dette vil vi implementere merknaden vår trinnvis, og gradvis bygge opp en mer inngående forståelse av AOP-konsepter mens vi går.

Resultatet vil være en bedre forståelse av AOP og muligheten til å lage våre tilpassede vårkommentarer i fremtiden.

2. Hva er en AOP-kommentar?

For å raskt oppsummere står AOP for aspektorientert programmering. I hovedsak, det er en måte å legge til atferd til eksisterende kode uten å endre den koden.

For en detaljert introduksjon til AOP, er det artikler om AOP-punktkutt og råd. Denne artikkelen antar at vi allerede har grunnleggende kunnskap.

Den typen AOP som vi skal implementere i denne artikkelen er merkedrevet. Vi er kanskje kjent med dette allerede hvis vi har brukt våren @Transaksjonell kommentar:

@Transactional public void orderGoods (Order order) {// En serie med databasesamtaler som skal utføres i en transaksjon}

Nøkkelen her er ikke-invasiv. Ved å bruke annoteringsmetadata forurenses ikke kjernevirksomhetslogikken vår med transaksjonskoden. Dette gjør det lettere å resonnere, refaktorere og teste isolert.

Noen ganger kan folk som utvikler vårapplikasjoner se dette somSpring Magic ', uten å tenke så detaljert på hvordan det fungerer. I virkeligheten er det som ikke skjer spesielt komplisert. Når vi har fullført trinnene i denne artikkelen, vil vi imidlertid kunne lage vår egen tilpassede kommentar for å forstå og utnytte AOP.

3. Maven avhengighet

La oss først legge til våre Maven-avhengigheter.

For dette eksemplet bruker vi Spring Boot, ettersom konvensjonen over konfigurasjonsmetoden lar oss komme i gang så raskt som mulig:

 org.springframework.boot spring-boot-starter-parent 2.2.2.RELEASE org.springframework.boot spring-boot-starter-aop 

Vær oppmerksom på at vi har tatt med AOP-starter, som henter inn bibliotekene vi trenger for å begynne å implementere aspekter.

4. Lage vår tilpassede kommentar

Kommentaren vi skal lage er en som vil bli brukt til å logge hvor lang tid det tar en metode å utføre. La oss lage vår kommentar:

@Target (ElementType.METHOD) @Retention (RetentionPolicy.RUNTIME) offentlig @interface LogExecutionTime {} 

Selv om det er en relativt enkel implementering, er det verdt å merke seg hva de to metaanmerkelsene brukes til.

De @Mål kommentar forteller oss hvor kommentaren vår vil gjelde. Her bruker vi ElementType.Method, som betyr at det bare vil fungere på metoder. Hvis vi prøvde å bruke merknaden noe annet sted, ville ikke koden vår kompilert. Denne oppførselen er fornuftig, siden merknaden vår vil bli brukt til å utføre tid for loggmetode.

Og @Bevaring oppgir bare om merknaden vil være tilgjengelig for JVM ved kjøretid eller ikke. Som standard er det ikke, så Spring AOP kunne ikke se kommentaren. Dette er grunnen til at den er omkonfigurert.

5. Å skape vårt aspekt

Nå har vi vår kommentar, la oss lage vårt aspekt. Dette er bare modulen som vil kapsle inn vår tverrgående bekymring, noe som er vårt tilfelle loggføring av metodeutførelse. Alt det er er en klasse, kommentert med @Aspect:

@Aspect @Component public class ExampleAspect {}

Vi har også tatt med @Komponent kommentar, ettersom klassen vår også må være en vårbønne for å bli oppdaget. I hovedsak er dette klassen der vi vil implementere logikken som vi vil at vår tilpassede kommentar skal injisere.

6. Lage vårt snarvei og råd

La oss nå lage vårt snarvei og råd. Dette vil være en kommentert metode som lever i vårt aspekt:

@Around ("@ annotation (LogExecutionTime)") public Object logExecutionTime (ProceedingJoinPoint joinPoint) throw Throwable {return joinPoint.proceed (); }

Teknisk sett endrer dette ikke oppførselen til noe ennå, men det er fortsatt ganske mye som trenger analyse.

Først har vi kommentert metoden vår med @Rundt. Dette er vårt råd, og rundt råd betyr at vi legger til ekstra kode både før og etter metodeutførelse. Det finnes andre typer råd, for eksempel før og etter men de vil bli utenfor rekkevidden for denne artikkelen.

Neste, vår @Rundt merknader har et punktuttrykk. Vår snarvei sier bare: ‘Bruk dette rådet en hvilken som helst metode som er merket med @LogExecutionTime. ' Det er mange andre typer punktkutt, men de vil igjen bli utelatt hvis omfang.

Metoden logExecutionTime () i seg selv er vårt råd. Det er et enkelt argument, FortsetterJoinPoint. I vårt tilfelle vil dette være en kjøringsmetode som er merket med @LogExecutionTime.

Til slutt, når den merkede metoden ender med å bli kalt, hva som vil skje er at vårt råd vil bli kalt først. Så er det opp til vårt råd å bestemme hva du skal gjøre videre. I vårt tilfelle gjør vårt råd ingenting annet enn å ringe fortsette(), som bare kaller den opprinnelige kommenterte metoden.

7. Logging av vår gjennomføringstid

Nå har vi skjelettet vårt på plass, alt vi trenger å gjøre er å legge til litt ekstra logikk i rådene våre. Dette vil være det som logger utføringstiden i tillegg til å kalle den opprinnelige metoden. La oss legge til denne ekstra oppførselen i vårt råd:

@Around ("@ annotation (LogExecutionTime)") public Object logExecutionTime (ProceedingJoinPoint joinPoint) throw Throwable {long start = System.currentTimeMillis (); Objekt fortsett = joinPoint.proceed (); lang kjøringstid = System.currentTimeMillis () - start; System.out.println (joinPoint.getSignature () + "utført i" + kjøringstid + "ms"); tilbake fortsett; }

Igjen, vi har ikke gjort noe som er spesielt komplisert her. Vi har nettopp registrert gjeldende tid, utført metoden og deretter skrevet ut hvor lang tid det tok til konsollen. Vi logger også metodesignaturen, som er gitt for å bruke joinpoint forekomst. Vi ville også kunne få tilgang til andre informasjonsbiter hvis vi ønsket det, for eksempel metodeargumenter.

La oss nå prøve å kommentere en metode med @LogExecutionTime, og deretter utføre den for å se hva som skjer. Merk at dette må være en Spring Bean for å fungere riktig:

@LogExecutionTime public void serve () kaster InterruptedException {Thread.sleep (2000); }

Etter utførelse skal vi se følgende logget til konsollen:

ugyldig org.baeldung.Service.serve () utført i 2030ms

8. Konklusjon

I denne artikkelen har vi utnyttet Spring Boot AOP for å lage vår egendefinerte kommentar, som vi kan bruke på vårbønner for å gi dem ekstra oppførsel i løpetid.

Kildekoden for applikasjonen vår er tilgjengelig på GitHub; dette er et Maven-prosjekt som skal kunne kjøre som det er.