Aspect Oriented
programming
with AspectJ
Rebora Federico
INTRODUZIONE
• Concern
– Ogni sistema software è composto da concern modulari e
concern di sistema.
– Si prenda come esempio un piccolo editor di figure
geometriche:
Point, Line e FigureElement
sono esempi di concern di
modulo che la programmazione
ad oggetti ben si adatta a
modellare utilizzando concetti
come ereditarietà e
polimorfismo
INTRODUZIONE
• Crosscutting Concern
– Le cose cambiano quando si tenta di rappresentare requisiti
come logging, tracing, gestione della sicurezza, autenticazione ed
altri.
– Si tratta di concern di sistema, spesso ortogonali o indipendenti
dagli altri, e che per loro natura risultano distribuiti in più
moduli.
– In questo caso si usa il termine crosscutting (traducibile come
“trasversale”).
INTRODUZIONE
• Esempio
– Osservando il codice di org.apache.tomcat notiamo che
funzionalità come l’XML parsing (sono colorate in rosso le
parti di codice interessate) vengono ben modellate con la
OOP.
INTRODUZIONE
• Esempio
– Osserviamo invece che il codice che gestisce il logging viene
distribuito in quasi tutte le classi. Questo è un classico esempio
di crosscutting concern.
AOP
• Programmazione Aspect Oriented
– La nascita dell’Aspect Oriented Programming (AOP) si deve a
XEROX PARC (Palo Alto Research Center) negli anni 90.
– Concetto “trasversale” alla programmazione ad oggetti (anche
se si integra con essa) in quanto ci aiuta ad affrontare in maniera
“elegante” problematiche che riguardano l’applicazione nel suo
insieme.
– L’AOP si occupa di trasformare in “moduli” i crosscut concern
similmente a come il java trasforma in “moduli” (classi) i
concern comuni.
AspectJ
• Cosa è AspectJ?
– Per sperimentare i benefici del nuovo paradigma, si è utilizzato
AspectJ, un’estensione AOP di Java, sviluppato da Gregor
Kiczales ed il suo gruppo alla Xerox PARC ed ora integrato nel
progetto Eclipse, un potente ambiente di sviluppo Open Source.
E’ possibile scaricarlo liberamente insieme a documentazione e
sorgenti all’indirizzo internet http://eclipse.org/aspectj/
– AspectJ aggiunge a java il concetto di join point ed aggiunge un
limitato numero di costrutti che vedremo nel seguito.
AspectJ
• I join point
– Identificano dei punti nell’esecuzione di un programma.
– AspectJ fornisce vari strumenti (detti pointcut) per definire
questi punti come la primitiva call:
call(void Point.setX(int))
Identifica tutti i punti in cui viene chiamato il metodo che ha
come signature ”void Point.setX(int)” (metodo setX della classe
Point che ha come parametro un intero).
AspectJ
• I join point
– AspectJ permette di “mettere insieme” dei pointcut per
generarne altri utilizzando gli operatori logici and, or e not (&&,
|| e !):
call(void Point.setX(int)) || call(void Point.setY(int)))
si riferisce ad una chiamata di setX(int) o di setY(int) nella
classe Point
AspectJ
• Nominare un pointcut
– E’ possibile assegnare un nome ad un pointcut:
pointcut set():
call(void Point.setX(int)) || call(void Point.setY(int));
Il programmatore potrà riferirsi semplicemente a set() (se
visibile in quel punto del codice) senza dover riscrivere il codice
tutte le volte.
AspectJ
• Altri esempi di pointcut
– Il pointcut successivo si riferisce a tutti i metodi della classe
figure il cui nome inizia con “make”
call(void Figure.make*(..))
– Questo si riferisce a tutti i metodi public della classe Figure
call(public * Figure.* (..))
AspectJ
• Advice
– I pointcut stabiliscono dei punti nell’esecuzione del programma
e non si occupano di nient’altro. Per “fare” qualcosa quando si
raggiunge quel preciso join point utilizziamo gli Advice.
before(): set() {
System.out.println(“About to set”);
}
Il blocco di codice viene eseguito prima di eseguire il codice del
join point.
AspectJ
• Advice
– Allo stesso modo è possibile eseguire il codice dopo
l’esecuzione del join point tramite l’advice After():
after() return: set() {
System.out.println(“I have set”);
}
Esistono tre tipi di advice: after returning, after throwing e plain
after (viene eseguito in entrambi i casi).
AspectJ
• Context exposing
– I pointcut possono esporre parte del contesto di esecuzione nel
loro join point.
– I valori esposti da un pointcut possono essere utilizzati nel codice
dell’advice:
after(Point p, int x) returning:
call(void Point.setX(int)) && target(p) && args(x) {
System.out.println(p + “moved to: " + x);
}
Nell’esempio notiamo le primitive target ed args che servono a
pubblicare i valori di p ed x .
AspectJ
• Inter-type declarations
– Dichiarazioni indipendenti dalla gerarchia delle classi.
– Le inter-type declarations agiscono a livello statico (compiletime).
– Ad esempio vogliamo implementare un concern in un certo
numero di classi della nostra applicazione. In java potremmo
creare un’interfaccia ed implementarne i metodi in ciascuna
classe interessata.
– AspectJ ci fornisce uno strumento totalmente indipendente
dalle classi interessate per definire questo concern: le inter-type
declarations.
AspectJ
• Inter-type declarations
– Immaginiamo di implementare degli oggetti Screen che
“osservano” i nostri oggetti Point e vanno aggiornati ogni volta
che il Point che stanno osservando “cambia”.
– E’ possibile implementare questa funzione aggiungendo un
campo nella classe Point contente la lista degli oggetti che
stanno osservando quel punto.
aspect PointObserving {
private Vector Point.observers = new Vector();
...
}
Con questo semplice costrutto abbiamo aggiunto il campo
observers nella classe Point.
AspectJ
• Inter-type declarations
– Il campo observers è privato (quindi è visibile solo in
PointObserving).
– Per modificare la lista degli osservatori servono due metodi:
aspect PointObserving {
private Vector Point.observers = new Vector();
public static void addObserver(Point p, Screen s) {
p.observers.add(s);
}
public static void removeObserver(Point p, Screen s) {
p.observers.remove(s);
} ... }
AspectJ
• Inter-type declarations
– A questo punto basta aggiungere nel corpo dell’aspect:
pointcut changes(Point p): target(p) && call(voidPoint.set*(int));
after(Point p): changes(p) {
Iterator iter = p.observers.iterator();
while ( iter.hasNext() ) {
updateObserver(p, (Screen)iter.next());
}
}
static void updateObserver(Point p, Screen s) {
s.display(p);
}
Notiamo che il sorgente delle classi Screen e Point non è stato
assolutamente modificato e tutto il necessario per
implementare la funzionalità risiede in PointObserving.
AspectJ
• Aspetti
– Un aspetto è molto simile ad una classe in quanto può avere dei
campi e dei metodi propri oltre ad i crosscut dichiarati.
– AspectJ si occupa dell’istanziazione di un aspetto (non è il
programmatore ad usare un costrutto simile al new).
– Di default viene creata solo un’istanza per aspetto.
AspectJ
• Aspetti (Esempio)
aspect Logging {
OutputStream logStream = System.err;
pointcut set():
call(void Point.setX(int)) || call(void Point.setY(int));
before(): set() {
logStream.println("about to set");
}
}
AspectJ
• Utilizzare AspectJ
– Di seguito vedremo alcuni esempi di utilizzo della AOP nello
sviluppo di un’applicazione.
– Possiamo distinguere due categorie.
– I development aspects vengono facilmente rimossi al momento
della produzione (build) dell’applicazione.
– I production aspects invece vengono mantenuti ma tendono ad
interessare un numero ristretto di classi.
AspectJ
• Development aspects
– Servono a facilitare operazioni come il debugging, testing e
performance tuning.
– Usando AspectJ è possibile abilitare e disabilitare queste
funzionalità in qualunque momento.
– Senza AspectJ si renderebbe necessario manipolare il codice
ogni volta.
AspectJ
• Tracing
– Questo primo esempio ci mostra come aumentare la visibilità di
ciò che accade dentro la nostra applicazione
aspect SimpleTracing {
pointcut tracedCall(): call(void FigureElement.draw(GraphicsContext));
before(): tracedCall() {
System.out.println("Entering: " + thisJoinPoint);
}
}
– La variabile speciale thisJoinPoint contiene la signature del join
point interessato.
– Se volessimo fare il trace di un altro metodo basterebbe
cambiare il pointcut senza dover cambiare nemmeno una riga di
codice dentro il metodo vero e proprio.
AspectJ
• Profiling and Logging
– Con questo esempio mostriamo come è possibile esaminare
alcuni comportamenti della nostra applicazione.
– Ad esempio vogliamo contare quante volte viene chiamato il
metodo rotate della classe Line:
aspect SetsInRotateCounting {
int rotateCount = 0;
int setCount = 0;
before(): call(void Line.rotate(double)) {
rotateCount++;
}
before(): call(void Point.set*(int)) &&
cflow(call(void Line.rotate(double))) {
setCount++;
}
}
AspectJ
• Production aspects
– Rispetto ai development aspects, questi servono ad aggiungere
funzionalità alla nostra applicazione anziché limitarsi a darne una
maggiore visibilità.
– Di seguito vedremo alcuni esempi.
AspectJ
• Change Monitoring
– Vogliamo implementare una funzionalità che tenga traccia delle
figure che hanno subito una modifica in modo da eseguire il
refresh dello schermo
AspectJ
aspect MoveTracking {
private static boolean dirty = false;
public static boolean testAndClear() {
boolean result = dirty;
dirty = false; return result;
}
pointcut move():
call(void FigureElement.setXY(int, int)) ||
call(void Line.setP1(Point)) ||
call(void Line.setP2(Point)) ||
call(void Point.setX(int)) ||
call(void Point.setY(int));
after() returning: move() {
dirty = true;
}
}
AspectJ
• Conclusioni
– Esistono altre implementazioni di AOP per java e per C++
(maggiori informazioni sul sito http://aosd.net/) si è scelto di
prendere in esame AspectJ in quanto tra tutte è sicuramente
l’implementazione quella più matura ed ampiamente usata.
– Per maggiori informazioni riguardo l’uso di AspectJ è possibile
visitare la pagina ufficiale al seguente URL:
http://eclipse.org/aspectj/
Bibliografia
– The AspectJ Programming Guide
http://dev.eclipse.org/viewcvs/indextech.cgi/~checkout~/aspectjhome/doc/progguide/index.html
– Aspect Oriented programming con AspectJ
http://www.objectway.it/articles/0308_AOPAspectJ.pdf
– Aspect Oriented Programmi di Kiczales (articolo originale del
1997)
http://www2.parc.com/csl/groups/sda/publications/papers/Kiczales-ECOOP97/for-web.pdf
Scarica

AOP