Introduzione
Oggi il contenitore EJB fornisce servizi alla nostra
applicazione, per esempio sicurezza e gestione della
persistenza.
Il server EJB intercetta le chiamate e gestisce l'ambiente
per le nostre classi EJB, applicando gli aspetti ("servizi")
richiesti.
Nella metodologia Object Oriented non è possibile
esprimere questi aspetti in modo efficiente. L'unico
modo è l'inserimento in più classi del
codice a mano, con l'implicazione di una limitazione
dela flessibilità avendo gli aspetti un impatto
su più classi.
EJB è una soluzione standardizzata che aiuta
a risolvere il problema negli aspetti più comuni.
Figura 1 - La architettura EJB
L'Aspect
Oriented Programming (AOP) è una nuova tecnica
di programmazione sviluppata nel 1997 da Kiczales et
al. a Xerox Parc [1,2].
Gli ideatori di AOP hanno notato che esistono requisiti
a livello design, che sono facili da esprimere, ma difficile
da implementare perché hanno un impatto su più
classi.
Per migliorare la qualità e facilitare la manutenzione
del codice è utile scrivere in un punto solo
il codice che implementa una funzionalità. Ma
come si fa quando la funzionalità ha un impatto
su più classi? La vera innovazione dell'AOP è
la proposta di una soluzione per trattare questo problema.
Con AOP si scrive il codice che implementa la funzionalità
(chiamato "aspect" <-> "aspetto")
una sola volta, insieme ad istruzioni che dicono come
applicare la nuova funzionalità a più
classi.
AOP
introduce nuovi concetti e li esprime con nuovi vocaboli,
consentendo così al programmatore di rappresentare
i concetti EJB in un'altra prospettiva. AOP impatta
soprattutto sull'implementazione del server EJB, e quindi
non ha conseguenze importanti per il programmatore che
utilizza EJB, ma per quest'ultimo è lo stesso
utile conoscere i nuovi termini.
Per
esempio se vogliamo gestire la sicurezza senza usare
EJB, dobbiamo inserire in tante classi diverse codice
che controlla se l'accesso è permesso: la sicurezza
è un esempio tipico di "aspetto" AOP.
Ragionando in questo modo si può pensare anche
agli altri servizi EJB come aspetti AOP, ed immaginare
l'architettura EJB semplicemente come un'implementazione
specializzata di AOP con i servizi EJB come aspetti
preimpostati con un funzionamento standardizzato: in
questo scenario il deployment descriptor descrive come
applicare i servizi ("aspetti") EJB.
JBoss 4
Il gruppo JBoss ha pensato in questi termini nella realizzazione
della versione 4.0, basata su un framework AOP. Per
gli EJB, JBoss usa un class loader speciale che legge
il file di configurazione (deployment descriptor) e
aggiunge codice addizionale che chiama i servizi richiesti.
Per un'applicazione EJB standard non è cambiato
niente, solo il funzionamento interno di JBoss.
Gli sviluppatori hanno inoltre reso pubblico il funzionamento
di JBoss AOP, permettendo ad una classe normale (non-EJB)
di avere l'uso di servizi enterprise di tipo caching,
replicazione, transazioni e sicurezza, utilizzando un
semplice file XML molto simile ad un deployment descriptor.
JBoss AOP è un vero framework AOP che permette
di intercettare le chiamate di metodi, costruttori e
campi nelle classi, di introdurre metodi e campi, e
di usare metadati.
Concetti
AOP
AOP definisce nuovi vocaboli per poter esprimere i nuovi
concetti. Per implementare i concetti AOP in Java occorre
la manipolazione del byte-code o l'uso di un dynamic
proxy (java.lang.reflect.Proxy). Questo può essere
fatto in due modi: al momento della compilazione, con
un compiler speciale, o a run-time con un class loader
speciale.
Aspect
Un aspect è una decisione a livello di design
che ha un impatto ortogonale al livello d'implementazione,
ovvero il codice che realizza la funzione desiderata
è disperso in più classi ("cross-cutting").
Implementato usando advice, introduction, metadata e
pointcuts.
Advice/Interceptor
Un advice è un pezzo di codice aggiuntivo inserito
nelle classi per implementare un aspetto o una parte
di un aspetto. In JBoss è utilizzato un Interceptor:
una classe che implementa l'interfaccia org.jboss.aop.Interceptor
e che intercetta chiamate di metodi, costruttori e campi.
Per esempio, nell'ambito EJB, il servizio di sicurezza
può essere implementato usando uno o più
advice, introduction e metadata.
Figura 2 - Interceptors
Introduction
L'Introduction permette di introdurre nuovi metodi e
campi nella classe. E' anche possibile cambiare la superclasse
ed le interfacce che la classe implementa. Finalmente
arriva l'eredità multipla in Java!
L'Introduction
è un concetto molto importante per l'AOP. Gli
esperti dicono che il 50% di AOP è introduction.
Mixin
Mixin è una classe usata per implementare
introduction. Essa contiene il codice dei metodi/campi
da introdurre.
Metadata
I Metadati sono dati aggiuntivi che possono essere
associati ad una classe o ad un oggetto staticamente
o dinamicamente. I Metadati non sono un concetto strettamente
collegato ad AOP, essendo definito in JSR 175 [3], ed
introdotto in JDK 1.5.
Per esempio, per transazioni EJB è possibile
specificare per ogni metodo nel deployment descriptor
attributi come Required, Supports, ecc.
Un interceptor per le transazioni può usare questi
dati per decidere come gestire le transazioni, e aggiungere
dati (transaction context) dinamicamente per ogni oggetto
coinvolto in una transazione.
Pointcuts
Un pointcut specifica dove (a quali classi, metodi)
applicare advice, introduction e metadata alle classi
normali Java. Per JBoss AOP un pointcut è definito
usando XML in un modo molto simile ad un deployment
descriptor. Questo vuol dire che non c'è bisogno
di imparare un nuovo linguaggio per usare AOP. Per AspectJ
(il primo è più famoso AOP per Java) invece,
è necessario imparare una nuova sintassi per
esprimere i concetti AOP.
Weawing
Il weawing consiste nel processo di effettuare inserimento
del codice che implementa gli aspetti nelle classi normali
Java.
Per JBoss AOP, il classloader legge il file di configurazione
che contiene i pointcuts, e applica gli aspetti a run-time.
AspectJ invece usa un compilatore speciale.
POJO
POJO è una classe normale (non-EJB) Java.
(Plain Old Java Object).
JBoss AOP
Definire un Interceptor
L'interfaccia org.jboss.aop.Interceptor contiene solo
due metodi, getName e invoke.
Per le classi per cui è applicato, JBoss inserisce
una chiamata al metodo invoke, in altre parole invoke
è chiamato per ogni invocazione, come mostrato
nella figura 2.
Con JBoss AOP non è possibile dire che vogliamo
usare l'interceptor solo per un particolare metodo.
Questo vuol dire che dentro l'interceptor può
essere necessario controllare il nome del metodo e prendere
una decisione basata sul nome del metodo.
public
interface Interceptor {
public String getName();
public InvocationResponse invoke(Invocation
invocation)
throws Throwable;
}
Invocation contiene il nome del metodo/costruttore o
campo, e i parametri.
Sotto
è mostrata la classe TracingInterceptor dalla
cartella docs/oreilly-aop/example1 fornita con JBoss-AOP
import
org.jboss.aop.*;
import java.lang.reflect.*;
public
class TracingInterceptor implements Interceptor {
public String getName() { return "TracingInterceptor";
}
public InvocationResponse invoke(Invocation
invocation)
throws Throwable{
String message = null;
if (invocation.getType() ==
InvocationType.METHOD){
Method method =
MethodInvocation.getMethod(invocation);
message = "method:
" + method.getName();
}
else if (invocation.getType()
== InvocationType.CONSTRUCTOR){
Constructor c =
ConstructorInvocation.
getConstructor(invocation);
message = "constructor:
" + c.toString();
}
else{
// Do nothing for fields.
Just too verbose
return invocation.invokeNext();
}
System.out.println("Entering
" + message);
InvocationResponse rsp = invocation.invokeNext();
System.out.println("Leaving
" + message);
return rsp;
}
}
Tramite
la classe helper org.jboss.aop.MethodInvocation, si
può ottenere un riferimento al metodo. La TracingInterceptor
non fa altro che scrivere un messaggio prima e dopo
l'invocazione del metodo o costruttore. Si noti che
è necessario inserire il codice "invocation.invokeNext()"
in modo che JBoss AOP chiami altri Interceptor nella
catena d'interceptor per una classe e finalmente il
metodo/costruttore vero.
Definire
dove applicare l'interceptor (il pointcut)
JBoss AOP usa un file XML per definire un pointcut.
Si noti che è possibile definire il pointcut
solo a livello di classe, non a livello di metodi nella
classe.
<?xml
version="1.0" encoding="UTF-8"?>
<aop>
<interceptor-pointcut class="POJO">
<interceptors>
<interceptor class="TracingInterceptor"/>
</interceptors>
</interceptor-pointcut>
</aop>
Per
JBoss AOP standalone è necessario che il file
XML abbia il nome META-INF/jboss-aop.xml. Per l'uso
d'AOP dentro JBoss, è possibile fare il deploy
di un file chiamato *-aop.xml, o un jar con META-INF/jboss-aop.xml.
Usare
JBoss AOP fuori dell'application server JBoss (standalone)
Per fare funzionare l'esempio1 fuori da JBoss, è
necessario di aggiungere al classpath javassist.jar,
jboss-common.jar e jboss-aop.jar e usare un class loader
speciale.
cd
docs/oreilly-aop/example1
setenv CLASSPATH $CLASSPATH:.:
$JBOSS_AOP/jboss-common.jar:
$JBOSS_AOP/jboss-aop.jar:$JBOSS_AOP/javassist.jar
javac *.java
java -Djava.system.class.loader =
org.jboss.aop.standalone.SystemClassLoader
POJO
Metadata
Si possono aggiungere metadati nel file XML o nell'interceptor.
Poiché l'interceptor intercetta tutte le chiamate
per una classe, un uso interessante dei metadati è
decidere quale metodi intercettare. Il Pointcut sotto
fa parte dell'esempio2, e aggiunge metadata ai metodi
get, set, e main della classe POJO.
<class-metadata group="tracing" class="POJO">
<method name="(get.*)|(set.*)">
<filter>true</filter>
</method>
<method name="main">
<filter>true</filter>
</method>
</class-metadata>
Per
accedere ai metdadati dentro l'interceptor si usa il
metodo getMetadata:
String
filter = (String)invocation.getMetaData("tracing",
"filter");
if (filter != null && filter.equals("true"))
return invocation.invokeNext();
Conclusioni
Questa è sola una breve introduzione
a JBoss AOP. La documentazione sul sito di JBoss [4,5]
spiega in modo dettagliato come usare servizi standard
JBoss, quali per esempio le transazioni. Il gruppo JBoss
ha realizzato un prodotto all'avanguardia con la nuova
versione 4 basata su AOP. Gli sviluppatori hanno inoltre
reso pubblico il funzionamento di JBoss AOP, creando
una alternativa interessante per chi usa JBoss. L'uso
d'AOP apre nuove possibilità per migliorare la
qualità del codice e consente molto più
controllo al programmatore che l'EJB.
Infatti, si può pensare ad EJB come un'implementazione
ristretta di AOP.
Naturalmente EJB ha il grande vantaggio di essere standardizzato.
JBoss AOP ha lo svantaggio che è necessario usare
un class loader JBoss. Questo vuol dire che per ora
non è possibile utilizzarlo con un altro application
server.
JBoss AOP ha il vantaggio di avere già servizi
prescritti di tipo EJB che si può facilmente
usare, ma per chi vuole usare AOP con qualsiasi server
EJB, ci sono almeno tre alternative:
- Nanning
(http://nanning.snipsnap.org)
- Aspectj(http://www.eclipse.org/aspectj)
- AspectWerkz(http://aspectwerkz.codehaus.org/)
AspectWerkz
è simile a JBoss AOP poiché usa un file
XML per specificare i pointcuts e un class loader
speciale, ma è in grado di modificare anche
le classi dentro un application server.
Bibliografia
[1] Kirczales et al - "Aspect-oriented programming",
Springer-Verlag, Giugno 1997.
[2] http://aosd.net - Il sito ufficiale dell'AOSD steering
committee.
[3] http://www.jcp.org/en/jsr/detail?id=175 - Sito SUN
per JSR 175.
[4] http://www.jboss.org/developers/projects/jboss/aop
- Home per JBoss AOP.
[5] http://www.onjava.com/pub/a/onjava/2003/05/28/aop_jboss.html
- Articolo introduttivo.
|