Talán felvetődött az olvasóban - ha webes fejlesztéssel foglalkozik - hogy a feladatok előtti és utáni tevékenységek koordinálása igen hasonló ahhoz, amikor egy webszerverre csupán adatot meghatározott helye(ke)n keresztül lehet küldeni. Vagy például .NET esetén az objektumoknak saját kontextus adása után az odaérkező üzenetek elkapása is értelmezhető egyfajta aspektus-kezelésként. (Sajnos pointcut és inter-type declaration nélkül mégiscsak egyfajtaként...)
Valóban, az aspektus orientál programozás - sarkított - alapötlete az üzenetek elfogása még a célhoz érésük előtt. Hiszen ha tudom, éppen milyen aspektusban vagyok, akkor meg tudom mondani, ez az üzenet mit jelent számomra. S bár ennél jóval többről szól az AOP, de megértésének az alapja lehet ez.
A módszer néhány alapvető fogalmat használ. Tekintsük át ezeket a korábbi példa ismeretében. A könnyebb átláthatóság kedvéért ismét beszúrom a példaaspektust:
before() : greeting() { System.out.println("[A fontos metodus elindul]"); }
after() : greeting() { System.out.println("[A fontos metodus lefutott]"); }
}
Join point (belépési pont)
A join point az aspektus orientált programozás - AspectJ-s megközelítésének mindenképp - központi eleme. Join point kisebb megszorításokkal a program bármely azonosítható futási pontja lehet: egy metódus hívása, egy változó értékadása etc.
Például, ha meghívjuk a Fontos osztály fontosMetodus-át, akkor a kimenetre szöveget írunk. Általánosan fogalmazva: Ha valami történik, akkor valami lefut. Ennek különböző fajtáit foghatjuk meg a join pointokkal.
Természetesen nem minden ilyen pont érdekes, csupán kizárólag azok, melyeket valamilyen környezetbe - mint aspektusba - szeretnénk helyezni. Például egy inicializáló értékadás a konstruktorban érdektelen lehet, míg ha az egy fontos banki művelet része, akkor minden bizonnyal a tranzakció és a biztonság aspektusából máris érdekessé válik.
Pointcut
A pointcut-ok tartalmazzák és fogják egybe az alkalmazás join pointjait. őket definiáljuk, hiszen a join pointok implicite a valós osztályokban vannak.
A pointcut lényegében filterként működik: adott minta szerint szűri ki azokat a join pointokat, amelyekre igaz vagy hamis az állítás. (Ezt a igaz/hamis értéket az advice-oknál - a teendőknél - fogjuk használni.)
pointcut minden olyan hívást el fog kapni, ami a Fontos osztály setEgyenleg metódusához intéződött egy Kliens osztályú objektumtól tetszőleges paraméterrel.
Pointcutokat számos más módon és más műveletre is meghatározhatunk. Ezen lehetőségekről érdemes tájékozódni az AspectJ dokumentációjából, mert komoly különbségek adódnak a látszatra akár hasonló megoldásokból is (call() versus execution()).
Advice (tanács, itt: teendő)
Az advice határozza meg, mi történjen az adott join pointnál (vagy join pointok csoportjánál, amit pointcuttal határozuk meg). Három módon avatkozhatunk a futásba:
A before advice a join-point elött,
Az after advice a join-point futása után,
Az around advice speciális advice pedig a futás közben fut, lényegében kiváltva a join pointot.
Az alábbi kódrészletben a before advice egy 'A fontos metódus elindult' üzenetet fog küldeni a metódus futása elött.
before() : greeting() { System.out.println("[A fontos metodus elindul]"); }
Inter-type declaration
Az osztályok életébe való statikus beavatkozás. Segítségével az aspektus által érintett osztályoknak új adattagokat és metódusokat vezethetünk be.
Az alábbi aspektusban két osztály számára deklarálunk tagokat illetve biztosítunk egy metódust azok összekapcsolására. (Példa: AOSD.NET)
class Foo { ... } // izék class Bar { ... } // bigyók
aspect Linking { //kapcsolatot tart fent az izék és a bigyók között
private Set Foo.bars = new Hashset(); private Set Bar.foos = new Hashset();
static public link(Foo f, Bar b) { f.bars.add(b); b.foos.add(f); } }
Aspect (aspektus, nézőpont)
Az aspektus az AspectJ-nek az, ami a Javanak az osztály - szintaktikájában és szerkezetében nagyban igazodik is hozzá. Szintén tartalmazhat adattagokat és metódusokat, lehet abstract - de egyben magába foglalj pointcutokat, adivceokat és.további elemeket.
Az AOP formális meghatározását ezen keretek között nem tartanám fontosnak (az Irodalom részben több hivatkozás is mutat rá), de felhívnám a figyelmet arra a közkeletű tévedésre, miszerint az üzenetek elkapása (interception) és az attribútumok együttes használata az aspektus orientált programozás. Ez így nem áll meg, mint az akár csak a fenti felsorolásból is látható. Hasonlóan, hogy attól sem lesz programunk objektum orienált, ha minden programblokkot a class szóval kezdünk.
Az alapvető összetevőket már ismerjük. Az elv ami mindezt összefogja, vázlatosan a következő:
Azonosítjuk a lényegi feladatokat (például egy átutalás)
Azonosítjuk azokat a feladatokat, amik ezeken a fő feladatokat 'átszelik', metszik. (Például az authentikáció több osztályban is szerepelhet)
Megvalósítjuk - osztályok segítségével - a feladatokat
Az aspektusokkal meghatározzuk, ezek milyen viszonyban vannak egymással.
A weaver összeállítja a teljes rendszert.
A folyamatot a következőképpen szemléltethetjük:
3. ábra
Érdemes meggondolni azt, hogy az utolsó lépés a hagyományos OO módszerekkel nem így nézne ki! Ekkor ugyanis a sötétkék négyzetet piros és sárga téglatestek szabdalnák a keveredő kódok, feladatok miatt.
Fontos tudni, hogy az AspectJ fordítás után tökéletesen szabályos Java kódot állít elő, ezért az bárhol futtatható, ahol JRE rendelkezésre áll.