Itt jársz most: Kezdőlap > Alkalmazásfejlesztés > AOP alapok Spring keretrendszerben

Szűrő megjelenítése

AOP alapok Spring keretrendszerben

Építőelemek

Mielőtt belevágnánk, érdemes definiálni néhány alapvető kifejezést, mellyel találkozni fogunk AOP-s funkciók implementálása során. Cikkem bevezető jellege miatt ezúttal csak a legfontosabbak:

Aspect

A legalapvetőbb építőkő az AOP keretrendszerben az aspect. Az aspect az az eszköz, mely “keresztülvágja” az alkalmazás logikáját - ezért is használják az aspect-re a “crosscutting concern” kifejezést. Aspectben írhatjuk le azon funkciókat, melyek az alkalmazás futása során több különböző ponton kell, hogy megjelenjenek - ilyen például a tranzakciókezelés.

Join point

Egy olyan pontja az alkalmazásnak, ahol a tényleges üzleti logikát biztosító kód, és az aspectek találkoznak. Ez jelenthet metódus végrehajtást vagy egy kiváltódó kivételt, bár a Spring AOP keretrendszere csupán előbbit képes kezelni.

Advice

A join point-on végrehajtandó logika. Több fajtája lehet, melyekre még később visszatérek.

Pointcut

A pointcut egy predikátum, mely teljesülése esetén az adott joint point-on végrehajtódik a definiált advice - ez most valószínűleg még magyarázatra szorul, de később példa is lesz rá a cikkben.

Weaving

A weaving során linkeli a keretrendszer az aspect implementációkat az üzleti kódhoz. Történhet futási időben (a Spring AOP ezt a módszert támogatja) vagy fordítási időben is.

Az advice definiálása

Mint azt említettem az advice-oknak több fajtája is létezik, aszerint, hogy mikor futnak, futhatnak le. Ennek megfelelően a következő típusokat különböztetjük meg:

Before

A before típusú advice-ok a join point lefutása előtt hajtódnak végre. Jellegzetessége, hogy hozzáférhetünk többek között a join point-on átadott (metódus) paraméterek tartalmához.

AfterReturning

Az after returning advice-ok a before advice-okkal ellentétben a join point-on visszatérő metódus visszatérési értékéhez adnak hozzáférési lehetőséget.

AfterThrowing

Az after advice-okhoz hasonlóan a join point lefutását követően, de a metódus által kiváltott kivételhez férhetünk hozzá.

After

Az after függetlenül attól, hogy a metódus sikeresen vagy kivétellel tért vissza, mindenképpen lefut.

Around

A legnagyobb rugalmasságot adó advice fajta, mivel - mint a neve is mutatja - a join point köré ékelődik, tehát annak lefutása előtt és után is végrehajthatunk vele extra logikát. Míg az előző advice fajtáknak nem volt szüksége a tényleges join point paraméterként való átadására, az around megköveteli azt. Az advice logikán belül a paraméterként átadott ProceedingJoinPoint példány process() metódusával hajthatjuk végre a wrapelt hívást.

A pointcut definiálása

Bár a Spring AOP csak a metódus alapú join pointok definiálását teszi lehetővé, ahhoz biztosítja minden fontos AOP-s pointcut kifejezés használatát. Sőt, mivel beanekre illesztett join pointokról beszélünk, akár a bean nevére is illeszthetjük azt. Kicsit előre szaladtam, visszatérve a fontosabb kifejezésekre:

Execution

Talán a legalapvetőbb kifejezés, amit a legtöbbször fogunk használni. Az execution pointcut meghatároz egy metódus specifikációt, melyen a join pointunk ül majd. A kifejezésben használhatunk wildcardokat is, így általánosítva a pointcutot, de akár egészen pontosan is kifejezhetjük a kívánt metódus specifikációját (visszatérési típussal, paraméterekkel).

Within

A végrehajtott metódus a megadott típusok egyikében van definiálva. Például megadható egy teljes package is, ekkor a pointcut predikátum bármely olyan metódus végrehajtásakor igaz lesz, mely az adott package-ben található osztályok bármelyikében található.

This

A végrehajtott bean típusára alkalmaz szűrést. Tehát a pointcut igaz lesz, ha a végrehajtás alatt álló metódus egy olyan beanben van definiálva, melynek típusa a this kifejezés paraméterében megadott típus. Ebben és az alább lévő esetekben is az adott típus teljes minősített nevére lesz szükségünk.

Target

A metódus visszatérési típusára alkalmaz szűrést. A pointcut igaz lesz, ha a metódus a target kifejezés paramétereként megadott típusú példánnyal tér vissza.

Args

A metódus argumentumainak típusára alkalmaz szűrést. A pointcut ez esetben akkor lesz igaz, ha a végrehajtott metódusnak van az args kifejezés paramétereként megadott paramétere.

@Target

Az @ szimbólummal kezdődő kifejezések annotációkra, illetve azon jelenlétére szűrnek. Az @target kifejezés a metódust tartalmazó osztályon levő annotációkra alkalmaz szűrést.

@Args

A metódusnak átadott paraméterek futásidejű típusán lévő annotációkra alkalmaz szűrést.

@Within

Olyan típusokra alkalmaz szűrést, melyek rendelkeznek a paraméterként megadott annotációval.

@Annotation

A pointcut a megadott annotáció jelenlétére figyel majd. Tehát amennyiben a join pointon levő metódus rendelkezik a megadott annotációval, az advice végrehajtásra kerül.

Akkor jöhet a gyakorlat…

Kicsit hosszú lett a bevezető, de nézzük, hogyan fog kinézni egy advice implementáció. Először is, engedélyezni kell az AOP feldolgozást a Spring számára, az @EnableAspectJAutoProxy annotáció segítségével. Ezt megtehetjük az alkalmazásunk bármelyik @Configuration annotációval ellátott osztályán, vagy Spring Boot alkalmazás esetén akár a @SpringBootApplication annotációval ellátott belépési ponton is (röviden a main-t tartalmazó osztályon).

@Configuration
@EnableAspectJAutoProxy
public class ApplicationContextConfig {
	// ...
}

Miután ez megvan, készítsünk egy osztályt, melyben az aspect logikáját helyezzük majd el. Persze mindenekelőtt fontos megtervezni, milyen advice-ra lesz szükségünk, mire és milyen logikát szeretnénk ültetni. Az osztálynak mindenesetre szüksége lesz az @Advice annotációra, ezzel jelezzük ugyanis a framework számára, hogy az osztály egy advice implementációt fog tartalmazni. Fontos megjegyezni, hogy ezzel még nem kerül be a Spring dependency injection kezelése alá, így legalább egy @Component annotációra még szükségünk lesz - így persze lehetőségünk nyílik arra is, hogy függéseket biztosítsunk az advice számára.

@Aspect
@Component
public class ResponseFillerAspect {
	// …
}

A következő lépés a tényleges advice implementálása. A logika belépési pontját tartalmazó metódus neve bármi lehet, a paraméterei és visszatérése ugyanakkor viszonylag kötött. Az advice típusát a megfelelő annotációval tudjuk jelezni, attribútumaként a pointcut kifejezés kötelező, illetve minden típusnak megvannak a saját egyéni attribútumai is. Az alábbiakban két rövid példa látható, természetesen magyarázattal.

@Around(value = "execution(org.springframework.http.ResponseEntity "
	+ "hu.psprog.leaflet.web.rest.controller.*.*(..)) "
	+ "and @annotation(hu.psprog.leaflet.web.annotation.FillResponse)")
public Object aspectToWrapAnswer(ProceedingJoinPoint proceedingJoinPoint)
	// …
	Object methodResponse = proceedingJoinPoint.proceed();
	// …
	return methodResponse;
}

A fenti példa egy @Around típusú advice, mely a következő join pointra ültet logikát:

  • hu.psprog.leaflet.web.rest.controller package-ben található, tetszőleges paraméterekkel rendelkező és ResponseEntity-vel visszatérő metódus végrehajtása
  • de csak abban az esetben, ha rendelkezik a FillResponse annotációval.

Mivel az around advice-nak szüksége van a join point-ra, a ProceedingJoinPoint paramétert megkapja a metódus. A tényleges hívás a process() hívással hajtódik végre, addig és azután bármilyen logikával fel lehet tölteni az advice implementációt. Az advice végül visszatér a wrapelt metódus válaszával.

@AfterReturning(
   value = "execution(hu.psprog.leaflet.service.vo.EntityPageVO+ "
		+ "hu.psprog.leaflet.service.*.*(..))",
   returning = "entityPageVO")
void aspectToAutoHandleEntityPageParameters(EntityPageVO<? extends BaseVO> entityPageVO) {
	// …
}

Ez pedig egy after returning advice, mely akkor aktiválódik, ha a hu.psprog.leaflet.service package-ben található, tetszőleges paraméterekkel rendelkező metódus kerül végrehajtásra. A kifejezésben még egy érdekesség látható, ez pedig az EntityPageVO+, mely azt jelenti, hogy a metódusnak az EntityPageVO osztályt kiterjesztő osztály példányával kell visszatérnie. Ha a pointcut teljesül, kiemeli az entityPageVO nevű változóba a visszatérési értéket, és átadja az advice implementációnak - ezután az értékkel tetszőleges műveletet hajthatunk végre.

Nos ezzel bevezető jellegű cikkem végére értem. A részletes és teljes dokumentáció elolvasását mindenképpen javaslom az érdeklődőknek, mely az alábbi linken megtalálható:

Részletes dokumentáció az AOP-ről

Teljes aspect implementációk

Kommentek
Hozzászólok

Még senki nem szólt hozzá ehhez a bejegyzéshez.