You are on page 1of 8

JJ n.

3 marzo-aprile 2007

Programmazione AOP con AspectJ


di Mattero Baccan
` Dopo anni di programmazione strutturata, si e passati ad anni di programmazione ad oggetti. Ora si inizia a parlare di POP (Post Object Programming), e delle tecnologie correla` te. AOP (Aspect Oriented Programming), e appunto una di queste tecnologie. Vediamo di cosa si tratta, con esempi pratici e lutilizzo di un compilatore gratuito come AspectJ.

Matteo Baccan ` E uno specialista di progettazione e sviluppo C++, JAVA e AOP . ` ideatore del porE tale JobCrawler.it e speaker in importanti eventi Java (Javaday, JIP Day).

pubblicato su WWW.INFOMEDIA.IT stampa digitale da Lulu Enterprises Inc. stores.lulu.com/infomedia


Infomedia
` Infomedia e limpresa editoriale che da quasi venti anni ha raccolto la voce dei programmatori, dei sistemisti, dei professionisti, degli studenti, dei ricercatori e dei professori dinformatica italiani. Sono pi` di 800 gli autori che hanno realizzato per le teu state Computer Programming, Dev, Login, Visual Basic Journal e Java Journal, molte migliaia di articoli tecnici, presentazioni di prodotti, tecnologie, protocolli, strumenti di lavoro, tecniche di sviluppo e semplici trucchi e stratagemmi. Oltre 6 milioni di copie distribuite, trentamila pagine stampate, fanno di questa impresa la pi` grande ed u inuente realt` delleditoria specializzata nel campo della a programmazione e della sistemistica. In tutti questi anni le riviste Infomedia hanno vissuto della passione di quanti vedono nella programmazione non solo la propria professione ma unattivit` vitale e un vero a divertimento. ` Nel 2009, Infomedia e cambiata radicalmente adottando ` un nuovo modello aziendale ed editoriale e si e organizzata attorno ad una idea di Impresa Sociale di Comunit` , a partecipata da programmatori e sistemisti, separando le attivit` di gestione dellinformazione gestite da un board a comunitario professionale e quelle di produzione gesti` te da una impresa strumentale. Questo assetto e in linea con le migliori esperienze internazionali e rende Infomedia ancora di pi` parte della Comunit` nazionale degli u a sviluppatori di software. ` Infomedia e media-partner di manifestazioni ed eventi in ambito informatico, collabora con molti dei pi` imporu tanti editori informatici italiani come partner editoriale e fornitore di servizi di localizzazione in italiano di testi in lingua inglese.

Limpaginazione automatica di questa rivista e realizzata al ` 100% con strumenti Open Source usando OpenOffice, Emacs, BHL, LaTeX, Gimp, Inkscape e i linguaggi Lisp, Python e BASH

For copyright information about the contents of Java Journal, please see the section Copyright at the end of each article if exists, otherwise ask authors. Infomedia contents is 2007 Infomedia and released as Creative Commons 2.5 BY-NC-ND. Turing Club content is 2007 Turing Club released as Creative Commons 2.5 BY-ND. Le informazioni di copyright sul contenuto di Java Journal sono riportate nella sezione Copyright alla ne di ciascun articolo o vanno richieste direttamente agli autori. Il contenuto Infomedia e 2007 Infomedia e rila` sciato con Licenza Creative Commons 2.5 BY-NC-ND. Il contenuto Turing Club e 2007 Turing Club e rilasciato ` con Licenza Creative Commons 2.5 BY-ND. Si applicano tutte le norme di tutela dei marchi e dei segni distintivi. ` E in ogni caso ammessa la riproduzione parziale o totale dei testi e delle immagini per scopo didattico purch e vengano integralmente citati gli autori e la completa identicazione della testata. Manoscritti e foto originali, anche se non pubblicati, non si restituiscono. Contenuto pubblicitario inferiore al 45%. La biograa dellautore riportata nellarticolo e sul sito www.infomedia.it e di norma quella disponibi` le nella stampa dellarticolo o aggiornata a cura dellautore stesso. Per aggiornarla scrivere a info@infomedia.it o farlo in autonomia allindirizzo http://mags.programmers.net/moduli/biograa

focus

JAVA Journal

Programmazione AOP con AspectJ


Dopo anni di programmazione strutturata, si passati ad anni di programmazione ad oggetti. Ora si inizia a parlare di POP (Post Object Programming), e delle tecnologie correlate. AOP (Aspect Oriented Programming), appunto una di queste tecnologie. Vediamo di cosa si tratta, con esempi pratici e lutilizzo di un compilatore gratuito come AspectJ.
>> di Matteo Baccan (matteo.baccan@javajournal.it)

Perch AOP

rogettare una libreria di funzioni o un framework di classi, sicuramente unoperazione lunga e laboriosa. Occorre capire i problemi che si avranno, il modo col quale astrarli e generalizzarli, ma soprattutto prevedere, nel modo pi completo possibile, le nuove esigenze che si potrebbero avere, per evitare di trovarsi, durante lo sviluppo, in problemi architetturali. Esistono per delle esigenze orizzontali ad un framework, che dovrebbero far parte di tutte le classi, ma, per evitare di sporcare tutto il codice, si tende a non integrarle, ad integrarle parzialmente, o a delegarle al programma chiamante. Esempi classici di queste esigenze sono la gestione degli errori, il debug degli oggetti, il controllo formale dei parametri e cos via. Cosa vuol dire affrontare in modo generalizzato queste problematiche? Sicuramente significa creare dei sorgenti ridondanti, copiare dei frammenti di codice da un metodo allaltro, astrarre esigenze in interfacce ed obbligare le classi ad implementarle. Fino ad arrivare agli assurdi delle dipendenze circolari, schemi dai quali diventa complicato uscire. Quando poi lesigenza orizzontale muta, ne risente lintero framework, creando delle destabilizzazioni nel codice: se il tutto non stato progettato pi che bene, ci si pu trovare di fronte alla riscrittura di varie classi, che non dipendono direttamente dalla modifica della funzionalit orizzontale, ma semplicemente sono impattate in quanto utilizzatrici dirette della funzionalit ormai obsoleta.

Lo scopo di AOP quello di isolare unesigenza orizzontale, racchiuderla allinterno di una regola (aspect), ed applicarla solamente nei punti in cui serve, senza impattare minimamente la classe che ne trarr vantaggio. Questo vuol dire che, le persone che sviluppano una classe e quelle che la arricchiscono con un aspect, possono tranquillamente far parte di due team di sviluppo diversi, dato che lavorano su due set di classi differenti, che si fondono per creare un unico bytecode, che sar quello che andr ad essere utilizzato in fase di runtime. Sorgenti diversi, impatti minimi al cambio delle funzionalit delle classi, possibilit di aggiungere comportamenti senza modificare il framework che deve essere arricchito, queste sono le caratteristiche principali di AOP.

AspectJ Lo strumento di cui parleremo in questo articolo AspectJ, un compilatore gratuito, che si appoggia a javac e permette di integrare, allinterno delle proprie classi, degli aspect. Questo compilatore facilmente scaricabile da: http: //www.eclipse.org/aspectj/, e si installa con la classica invocazione da riga comando: java -jar aspectj1.5.0.jar. Una volta installato, viene creata una cartella su disco, generalmente c:\aspectj1.5\, che conterr sia il compilatore che le librerie per poterlo utilizzare. Il passo successivo sar quello di mettere in path la directory c:\aspectj1.5\bin e in classpath il jar di AspectJ: c:\aspectj1.5\lib\aspectjrt.jar.

54

n.3 - marzo/aprile 2007

JAVA Journal
Chiaramente, la partenza di tutto un framework preventivamente costituito, sul quale vogliamo aggiungere il controllo daccesso. Perch non modificare direttamente il framework? Le ragioni potrebbero essere molteplici, come il non disporre dei sorgenti del framework, oppure il dover applicare tali modifiche solo ad un progetto che lo utilizza, ma non a tutte le applicazioni che lo utilizzano, evitando quindi di aggiungere codice inutile dove non serve. Se vogliamo analizzare la problematica, dal punto di vista dellObject Orientation (OO), il primo approccio che potrebbe venire in mente, in questo caso, quello di creare una classe di controllo accessi, modificare il sorgente della classe che deve aggiungere la funzionalit, inserirvi un metodo di controllo e modificare tutti i sottometodi che devono essere controllati, con la chiamata a questo metodo. Questo approccio obbliga, necessariamente, la modifica di gran parte del codice della classe, rendendo, di fatto, il controllo daccesso una funzionalit obbligatoria, in ogni ambito in cui la classe utilizzata. In unottica di riutilizzo del framework, si traduce nel aver introdotto qualcosa che servir solamente in un certo caso specifico, ma non nella totalit dei casi in cui verr utilizzato il framework stesso. Ne consegue una struttura similare a quella presente in Figura 1. Vediamo invece cosa cambia, nel momento in cui decidessimo di creare un aspect. Ci che viene stravolto totalmente il modo col quale applicare il controllo daccesso. Non occorre pi modificare le classi o i framework che devono supportare questo nuovo requisito, ma basta creare singolarmente il requisito, allinterno di un aspect, definire quando deve essere applicato e compilarlo insieme al codice del framework. Questa modalit permette di aggiungere del codice, ad applicazioni gi scritte, senza bisogno di modificarle. Le classi quindi, non devono ereditare da un qualcosa, ma quel qualcosa che si inserisce nelle classi. Ne risulta, quindi, una struttura simile a quella mostrata nella Figura 2, dove non si parla pi di ereditariet della classe di controllo degli accessi, ma di utilizzo.

focus

FIGURA 1

Struttura delle classi senza AOP

Fatte queste due operazioni basilari, siamo pronti per utilizzare AspectJ e creare le prime applicazioni AOP. Iniziamo quindi ad introdurre alcuni concetti di base.

Concetti di base Alla base della programmazione AOP c il concetto di crosscutting concern (CC), traducibile in interesse trasversale. Quando si parla di CC, si fa riferimento ad un requisito che pu essere pensato in modo autonomo, ed applicato in pi punti, allinterno del progetto che si sta sviluppando, senza essere necessariamente legato alla funzionalit che si intende sviluppare. Il poter astrarre un requisito, per poi applicarlo in modo orizzontale, ci permette di racchiudere la problematica in quello che viene definito aspect. Allinterno di un aspect, sono poi presenti le regole che indicano dove applicarlo. Il vantaggio di un aspect appunto il fatto di essere racchiuso allinterno di un proprio sorgente, dove non vi dipendenza diretta rispetto alle classi dove verr applicato. Per questo motivo, possibile uno sviluppo parallelo di requisiti. Sar poi compito del compilatore, nel nostro caso AspectJ, fondere regole e classi, allinterno dello stesso framework. Proviamo ora ad approfondire questi concetti con degli esempi.

Log degli accessi Ipotizziamo di dover controllare tutti gli accessi ad una certa classe. Le ragioni potrebbero essere svariate: un controllo di utilizzo, un test di performance o lapplicazione di un controllo di accesso. Lidea quella di creare un aspect, in grado di intercettare tutti gli accessi ad un certo metodo di una certa classe, visualizzandoli a video.

FIGURA 2

Struttura delle classi con AOP

n.3 - marzo/aprile 2007

55

focus

JAVA Journal
zializzazione di un oggetto; Advice execution: allesecuzione di un Advice. Con queste direttive, si riescono a coprire tutte le casistiche di una normale struttura ad oggetti. Vediamo ora le caratteristiche che possono avere i singoli costrutti, per meglio comprendere come e quando applicarli

Classe Demo public class Demo { public static void main(String[] args){ Demo d = new Demo(); d.go(); } public Demo(){} public String cVar = ; public void go(){ metodo1( PAR1 ); System.out.println( passo 100 a Metodo2 [ +metodo2( 100 ) +] ); } public void metodo1( String cPar ){ System.out.println( Metodo1 chiamato con parametro stringa [ +cPar +]); } public String metodo2( int n ){ System.out.println( Metodo2 chiamato con parametro numerico [ +n +]); return valore di ritorno*2 ( +(n*2) +); } }

Applicazione di un Join Point

LISTATO 1

Elementi fondamentali della programmazione AOP Chiarita la differenza di approccio rispetto alla programmazione Object Oriented, vediamo di scendere maggiormente in dettaglio, rispetto a AOP, introducendo un set minimale di costrutti, con i quali possibile creare qualsiasi tipo di aspect e di conseguenza poter sfruttare appieno questo paradigma di programmazione. I costrutti che occorre conoscere sono: oin Point: il punto di esecuzione di un programma: il richiamo di un metodo o lassegnazione di una variabile distanza; Pointcut: il meccanismo che permette di selezionare su quali Join Point andr ad agire un Advice; Advice: il codice che deve essere eseguito nel Join Point selezionato dal Pointcut; Aspect: linsieme di Advice e Pointcut. In base a queste descrizioni, se volessimo definire cos un aspect potremmo dire: una regola che indica il punto dove deve essere eseguito del codice. Il concetto di base molto semplice, ma allo stesso modo molto potente. Vediamo ora di capire quali sono i Join Point sui quali possiamo agire: Method execution/call: durante lesecuzione o il richiamo di un metodo; Constructor execution/call: durante lesecuzione o il richiamo di un costruttore; Class initialization: allatto dellinizializzazione di una classe; Field read/write: alla scrittura o lettura in una variabile distanza; Exception handler: quando si verifica uneccezione; Object initialization/pre-initialization: allatto dellini-

Come abbiamo spiegato nel paragrafo precedente, un Join Point, pu essere applicato sia in fase di esecuzione, sia in fase di richiamo di un certo metodo. La domanda pi spontanea che pu venire in mente : perch questa differenza? In effetti, aggiungere del codice in un solo punto, allinterno di un metodo, o aggiungerlo in ogni sua esecuzione, non cambia il risultato che si vuole ottenere. Cambia per a livello di risparmio di codice e cambia soprattutto se non si pu modificare direttamente il sorgente della classe che intendiamo controllare. Partiamo da un caso reale: si vuole condizionare lutilizzo di un certo metodo di una certa classe. Ipotizziamo che, tale metodo, sia allinterno di una classe di cui disponiamo il sorgente. In questo caso, il punto migliore per poter applicare laspect nel momento dellesecuzione, quindi dentro il metodo stesso. Se per il metodo non ci stato dato in chiaro, perch contenuto in una classe di cui abbiamo solo la libreria (.jar), lunico modo con cui possiamo applicare laspect al momento del suo utilizzo. Sicuramente questo secondo modo di utilizzare un aspect pi prolisso, ma lunico modo col quale possiamo applicarlo in questo contesto.

Esistono delle
esigenze orizzontali ad un framework, che dovrebbero far parte di tutte le classi

56

n.3 - marzo/aprile 2007

JAVA Journal
Call / Execution Proviamo quindi a creare un Aspect, partendo dalla classe Demo presente nel Listato 1: La classe desempio dispone di due metodi. Il primo non restituisce alcun risultato, mentre il secondo, restituisce un risultato String. Quello che dobbiamo creare ora un aspect, come illustrato di seguito:

focus

Lidea quella di
creare un aspect, in grado di intercettare tutti gli accessi ad un certo metodo di una certa classe
Esecuzione Prima Metodo1 chiamato con parametro stringa [PAR1] Dopo Prima2 Metodo2 chiamato con parametro numerico [100] Dopo2 passo 100 a Metodo2 [valore di ritorno*2 (200)] Leffetto quello di avere, prima e dopo lesecuzione dei due metodi, la visualizzazione di due messaggi. Chiaramente, se al posto dei messaggi ci fosse stato il controllo daccesso, avremmo risolto in modo ottimale la problematica, senza impattare la classe Demo.

Aspect
aspect Logging { pointcut primo_metodo(): call( void Demo.metodo1(String)); pointcut primo_metodo2(): execution( String Demo.metodo2(int)); void around(): primo_metodo() { System.out.println(Prima); proceed(); System.out.println(Dopo); } String around(): primo_metodo2() { System.out.println(Prima2); String cRet = proceed(); System.out.println(Dopo2); return cRet; } }

Un aspect sintatticamente molto simile ad una classe, di cui ricorda molto la struttura. Le differenze sono minime, ma importanti. Al posto del token class, per indicare un aspect, occorre scrivere aspect. Dopo la definizione del nome, possiamo passare a definire i pointcut e soprattutto i punti in cui devono agire: se al richiamo, call, del metodo o se alla sua esecuzione, execution. Una volta decisa la modalit, possiamo indicare quale gruppo di metodi, o singolo metodo, deve essere impattato. Nel nostro caso si deciso di indicare i due metodi della classe Demo. Ultimo punto da affrontare, quello di creare un advice, nel quale inserire il codice da eseguire. Anche ladvice ha una propria sintassi, data dal ritorno del metodo da arricchire, dalla modalit di utilizzo, nel nostro caso around, cio attorno al metodo che stiamo modificando, e da un proprio nome. Una volta definito, possiamo creare tutto il codice Java che desideriamo, ricordandoci di utilizzare il metodo proceed() per attivare il metodo che si stava modificando. Per compilare queste righe con AspectJ sufficiente chiamare il compilatore ajc passando, tramite una @, il nome del file contenente lelenco dei sorgenti da compilare, come in questo esempio: ajc @files.lst. A questo punto, invocando lesecuzione della classe Demo (java demo), otterremo louput:

Staticinitialization Altro punto interessante, nel quale applicare un aspect, linizializzazione di un oggetto tramite un costrutto static. Linizializzazione statica viene applicata tutte le volte in cui, in una classe, si ha lesigenza di creare un qualcosa di comune a pi istanze della classe stessa. Un esempio potrebbe essere la lettura di un file di configurazione, o la creazione dati statici. Tale inizializzazione avviene una sola volta sola, in tutto il programma. Potrebbe per essere interessante modificarne il comportamento o semplicemente notificarne lesecuzione. Anche in questo caso c un apposito pointcut da definire. Come si pu notare nel prossimo listato, la cosa che cambia la direttiva staticinitialization da passare al pointcut. Per quanto riguarda ladvice, la sintassi la stessa del caso precedente. La cosa che varia la presenza di void come valore di ritorno, dato che le inizializzazioni non hanno un valore di ritorno.

Staticinitialization
aspect Logging { pointcut primo_metodo() : staticinitialization( Demo );

n.3 - marzo/aprile 2007

57

focus

JAVA Journal
void around() : primo_metodo() { proceed(); } }

This/Target
aspect Logging { pointcut primo_metodo() : execution( * *.go() ) && this(Demo2); void around(): primo_metodo() { proceed(); } pointcut primo_metodo2() : execution( * *.go() ) && target(Demo); void around(): primo_metodo2() { proceed(); } }

Set/Get Cos come possiamo controllare laccesso ad un metodo, possibile controllare laccesso ad una variabile distanza, sia in lettura che in scrittura. Per fare questo possibile utilizzare un pointcut dove indicare quale variabile, di quale classe, andare a controllare. Per quanto riguarda ladvice, rimane tutto invariato, come nel caso del metodo:

Set/Get
aspect Logging { pointcut primo_metodo() : set( String Demo.cVal ); pointcut primo_metodo2() : get( String Demo.cVal ); void around() : primo_metodo() { proceed(); } String around() : primo_metodo2() { String c; c = proceed(); return c; } }

Questa modalit
permette di aggiungere del codice, ad applicazioni gi scritte, senza bisogno di modificarle

This/Target Unaltra modalit di attivazione, specificabile allinterno di un pointcut data dalla classe di attivazione. Ipotizziamo di avere pi classi che hanno un metodo comune chiamato go. Invece di specificare N pointcut, uno per ogni metodo di ogni classe, possiamo indicarne uno solo, utilizzando la wildcard *. Un esempio potrebbe essere pointcut pc(): execution( * *.go() ): dato qualsiasi metodo go, di qualsiasi classe, con qualsiasi valore di ritorno, gestisci il pointcut pc(). Chiaramente, tutto funziona correttamente, nel caso in cui ci siamo poche classi. Quando invece si utilizzano framework molto grandi, potrebbe essere necessario limitare la capacit di questo pointcut. Per questo sono stati introdotte le estensioni this( classe ) e target( classe ). Tramite questi due costrutti possibile limitare un pointcut allinterno di una certa classe (this) o solamente quando viene chiamato in una certa classe (target), come esposto in seguito: Args Altro filtraggio possibile sui pointcut dato dai parametri passati. infatti possibile utilizzare delle wildcard e parallelamente indicare che, i parametri gestiti dal metodo che si intende controllare, sono di un certo tipo. In seguito presente un esempio di utilizzo di args() collegato a tutti i metodi che ricevono come argomento un oggetto String.

Args
aspect Logging { pointcut primo_metodo() : execution( void *.*(*) ) && args( String ); void around() : primo_metodo() { System.out.println(Prima);

58

n.3 - marzo/aprile 2007

JAVA Journal
proceed(); System.out.println(Dopo); } }

focus

Advice Ora che abbiamo ben compreso come creare dei pointcut, vediamo quali tipo di esecuzione possibile far fare ad un advice. Oltre ad around, osservato negli esempi precedenti, possibile anche indicare before se vogliamo eseguire del codice prima del pointcut, o after, se lo vogliamo eseguire dopo. Da notare che un advice di per se molto simile ad un metodo, in quanto, come un metodo: Segue delle regole di accesso per essere eseguito Pu generare uneccezione Pu fare riferimento allaspect corrente tramite this Al contrario di un metodo per: Non ha un nome Non pu essere chiamato direttamente, il sistema che lo esegue Ha accesso ad alcune variabili valorizzate allinterno di this che possono servire a prendere informazioni sui join point catturati: thisJoinPoint Altro aspetto interessante degli advice quello di poter essere eseguiti dopo il ritorno di un valore da un metodo, oppure nel momento di uneccezione nel codice.

di questo tipo di programmazione, ma solo i concetti base, che permettono di capire come iniziare a programmare. Come si pu notare, il concetto base di AOP molto semplice. Servono poche righe di codice per arricchire in modo concreto, molte classi di nuove funzionalit. Piuttosto, il problema di AOP la sua giovane et. Il supporto per questo tipo di programmazione non ancora molto diffuso, anche se inizia a essere presente in alcuni ambienti di sviluppo. Inoltre, pensare in AOP, richiede un ulteriore passo in avanti, rispetto alla programmazione Object Oriented, passo di cui non si sente ancora lesigenza diffusa. Come tutte le cose, il tempo ci potr dare ragione o potr cancellare completamente questo approccio postobject oriented.

Un aspect una regola


che indica il punto dove deve essere eseguito del codice

Advice su eccezione Ultimi, ma non meno importanti, sono gli Advice su eccezione. Chiaramente, anche in questo caso, esiste una sintassi ben precisa, che ricalca molto quella vista per i metodi. Si tratta di definire sempre il momento in cui intercettare leccezione (ex: after), indicare che si vogliono gestire le eccezioni: throwing e definire su quali metodi si intende farlo, nel caso del listato seguente sono stati indicati tutti i metodi: * *.*().

Bibliografia [1] http://www.eclipse.org/aspectj/, AspectJ [2] http://www.eclipse.org, il progetto Eclipse [3] http://www.eclipse.org/aspectj/downloads.php, la pagina di download di AspectJ [4] http://www.baccan.it/index.php?sezione=webbit2 004, dove poter scaricare i sorgenti desempio analizzati in questo articolo.

Advice su eccezione
aspect Logging { after() throwing: call(* *.*()) { System.out.println(ERRORE); } }

Note Biografiche
Matteo Baccan uno specialista di progettazione e sviluppo C++, JAVA e AOP ideatore del portale JobCrawler.it e . speaker in importanti eventi Java (Javaday, JIP Day). Attualmente si occupa di analisi presso un importante operatore di telefonia mobile. Pu essere contattato tramite il suo sito http: //www.baccan.it.

Conclusioni Questo articolo unintroduzione alla programmazione AOP. Non sono stati toccati i concetti pi complessi

n.3 - marzo/aprile 2007

59