Aspekte auslagern – mit Spring AOP und AspectJ

Dienstag, 26. April 2011 von  
unter Fachartikel Architektur

Das Auslagern von modulübergeifenden technischen oder fachlichen Funktionalitäten, den „Cross Cutting Concerns“ (CCCs), in designierte Klassen und Nutzung der Klassen per Delegate Design Pattern, ist seit der Anwendung des „Separation of Concerns“ Prinzips erstrebenswert gewesen und für die Testbarkeit von Klassen mittels Unit-Tests von erheblicher Bedeutung. Solcherart isolierte Delegaten als Aspekte mit Hilfe des Dynamic Proxy Design Patterns beliebig ein- oder auszuschalten und in der Interaktion eines Workflows rein deklarativ (Annotation der Aspekte oder Deklaration per XML) dazwischenzuschalten ohne Änderungen im Code der eigentlichen Anwendung, ist neben ihrer Wiederverwendbarkeit ohne Code-Duplizierung nach dem D-R-Y Prinzip (Don’t Repeat Yourself) der eigentliche Vorteil beim Einsatz der „Aspektorientierten Programmierung“ (AOP).

Hierfür bietet Spring in den Versionen 2.0, 2.5.x und 3.x mit Spring AOP eine ausgereifte Lösung an, weshalb es in diesem Blog-Eintrag anhand eines kleinen Beispiels und einiger annotierter (Java 5 und 6) Beispiel-Klassen kurz vorgestellt werden soll. Zielgruppe des Artikels sind also Java Entwickler mit Spring Kenntnissen, die bereits Erfahrungen mit Spring AOP haben, oder diese und ähnliche Erfahrung ergänzen möchten. Vorweg soll kurz ein Vorteil des auf AspectJ basierenden Spring AOPs gegenüber AspectJ betont werden: Bytecode Modifikationen sind in Spring AOP nicht möglich, da es die bereits erwähnten Dynamic Proxies stattdessen zum von der eigentlichen Applikation unbemerkten Einklinken seiner Aspekte verwendet.

Dieses Dynamic Proxy Prinzip läßt sich am folgenden Diagramm einer das „Cache“ Business Interface implementierenden Klasse „SimpleCache“ mit der Methode „setCacheSize“ veranschaulichen, deren Aufruf von einer weiteren Aspect-Beispielklasse namens „PropertyChangeTracker“ geloggt wird:

[„Dynamic Proxy“ Prinzip, Quelle: springsource.com]

Man erkennt hier also bereits zwei „Cross Cutting Concerns“, die mit Hilfe von Aspekten als dynamische Proxies einklinkbar sind: Logging und Caching. Hier eine ausführlichere Auflistung typischer Aspekte:

Logging und Tracing (z.B. für erweitertes Logging von Datenbank Transaktionen)
Caching (Caching von Datenbank Abfrageergebnissen ohne die Datenbankzugriffs-Schicht zu ändern)
Transaction Management (Plug-In Transaktions Management Code verwenden, der nicht in den Java-Klassen der Datenbank Zugriffsmethoden auftaucht.)
Security (Plug-In Rollen-basierte Security Checks vor der Ausführung jeder Business Methode, ohne die Überprüfungen in jeder Business Method explizit durchzuführen)
Error Handling (Selbstdefinierte Exceptions ohne Erhöhung der Komplexität und Lesbarkeit des Applikations Codes durch ständig wiederkehrende Ausnahmebehandlungen)
Performance Monitoring
Ein-/Ausschalten zusätzlicher Business Regeln, ohne die Original Applikation ändern zu müssen (z.B. der Versand einer Bestätigungs-Mail nach abgeschlossener Order).

Hier nun die Erklärungen zu den angelegten Klassen „PropertyChangeTracker“ bzw. „RepositoryTracker“ und „CachingTracker“ für die Aspekte „Logging“ und „Caching“ auf der Grundlage eines SpringAopDemo Beispielprojekts, welches durch das Anlegen und Erweitern der benötigten Aspect-Klassen und deren deklarativer Aktivierung als dynamische Proxies vervollständigt wird.

Beispielprojekt

Der Einstieg in die Arbeit mit dem auf AspectJ basierenden Spring AOP wird in diesem Artikel anhand der annotierten Beispiel-Klassen veranschaulicht. Die Beispiele sind einfache Fragmente zur Aktivierung von  Logging und Caching in einer bereits vorhandenen Anwendung, welche z.B. als Java App läuft. Begonnen wird zum Einstieg mit den Klassen für den Logging Aspekt, dann folgt die Klasse für den Caching Aspekt.

Für das Erstellen des Beispielprojekts wurden die folgenden Pakete und Komponenten verwendet: Als flexible Entwicklungsumgebung die Spring Source Tool Suite 2.6.0. SR1 in der JEE 64bit Version [Download von: http://www.springsource.com/downloads/sts], weiterhin als Buildsystem Maven mindestens in der Version 2.2.1.

Erste Schritte

Ein Projekt als Beispielapplikation kann schnell mittels Dashboard (Spring Template Project) z.B. als Spring MVC Project mit dem Namen „SpringAopDemo“ angelegt werden:


Nach erfolgreichem Anlegen befindet sich innerhalb des Workspaces nun also ein konfigurierbares und ausführbares Projekt mit den folgenden relevanten Maven Dependencies (zusätzlich zu den log4j Paketen):

– spring-context-3.0.3.jar
– spring-aop-3.0.3.jar
– aopalliance-1.0.jar
– spring-asm-3.0.3.jar
– spring-beans-3.0.3.jar
– spring-core-3.0.3.jar
– spring-expression-3.0.3.jar
– spring-webmvc-3.0.3.jar
– spring-context-support-3.0.3.jar
– spring-web-3.0.3.jar
– aspectjrt-1.6.8.jar

Der Einsatz des Spring AOP Frameworks und die weitere Implementierung der Beispiel Klassen und deren Annotierung als Aspect werden im Folgenden an einfachen Beispielen erläutert. Zunächst aber die kurze  Erklärung der relevanten Begriffe „Join Point“, „Pointcut“, „Advice“, „Aspect“:

Join Point: ist ein Punkt in der Ausführung eines Programms, an dem man eine modulübergreifende Funktionalität (CCC), wie einen Logger-Methodenaufruf oder eine bestimmte Zuweisung, ausführen möchte.

Pointcut: ist ein Ausdruck (Pointcut Expression), der auf mehrere bestimmte JoinPoints zutrifft, diese also auswählt. Hierfür ist vor allem der Einsatz der „Pointcut Expression Language“ (PEL) relevant.

Advice: ist Code, der einen CCC repräsentiert und der an einem bestimmten Join Point oder üblicherweise an mehreren ausgewählten Join Points ausgeführt werden soll.

Aspect: ist üblicherweise eine Klasse, die Pointcuts and Advice kapselt. Hier ein Einstiegs-Beispiel :

@Aspect
public class MyAspect {   // the aspect class
[…]
// logging pointcut:
@Before( „execution(* de.binaris.springaop.demo.PersonRepository.*(..))“ )
public logPersonRepository() { // logging advice with logging code
[…]
}
[…]
}

Hier die Struktur des Beispiel Projekts mit der pom.xml:

Package Struktur SpringAopDemo Project
ASPEKTE MIT SPRING AOP- GRUNDLAGEN UND ANNOTATIONEN

Die verwendeten Beispiele können direkt innerhalb der Spring Source IDE als Java Applikationen „DemoLogging“ oder „DemoCache“ ausgeführt werden und verwenden eine MockPersonRepository Klasse zur Simulation der Daten aus dem PersonRepository Datenbank-Layer. Hier nun die Aspekte.

Logging als Aspekt (Cross Cutting Concern):

Die Logging Aufgabe besteht hier darin, jedesmal, wenn sich ein Attribut ändert, diese Änderung zu loggen. Hierfür wird die folgende Klasse „PropertyChangeTracker“ verwendet, die per @Aspect Annotation zu einem Aspekt wird, wobei die trackChange() Methode als „Advice Methode“ bezeichnet werden kann und an bestimmten JoinPoints aufgerufen werden soll (kurz bevor ein Attribut geändert wird), d.h. also immer, bevor eine setter-Methode aufgerufen wird, um ein Attribut zu ändern. Dies wird mit dem Pointcut Ausdruck in der @Before Annotation über der trackChange() Methode realisiert:

@Aspect
public class PropertyChangeTracker {
[…]

@Before(„execution(void set*(*))“)
public void trackChange() {
logger.info(„Gleich wird ein Attribut geändert…“);
}
}

Before Advice, ein Advice, der immer vor einem JoinPoint ausgeführt wird:

Der String, welcher der Before Annotation (als Beispiel eines Pointcuts) übergeben wird, ist eine
„Pointcut Expresssion“, die beschreibt wo der Pointcut zutreffen und ausgeführt werden soll und ist somit Bestandteil der Advice Methode, die vor jeder Methode ausgeführt werden soll, die den im Pointcut Ausdruck definierten Kriterien entspricht.

Erklärung des Before Pointcut Ausdrucks durch Zerlegung in seine Bestandteile:

Die Advice Methode „trackChange()“ wird vor der Ausführung jeder Methode ausgeführt, die den folgenden im Pointcut Ausdruck definierten Kriterien entspricht:
– die Methode hat den Rückgabetyp void,
– der Methodenname beginnt mit dem Prefix „set*“.
(z.B. setDataSource, setCacheSize, setFirstName, setLastName, etc.) und
– die Methode akzeptiert genau ein Argument (*).
Die Advice Methode wird jedesmal vor einer darauf zutreffenden Setter-Methode aufgerufen.

„Named Pointcuts“: explizit benannte symbolische Pointcut-Aliase für Aspect Definitionen

Verwendet wird weiterhin die bereits verwendete @Pointcut(execution… Annotation, jedoch wird diese Pointcut Annotation einer Methode namens „setterMethod“ mit leerem Funktionskörper zugeordnet:

@Pointcut(„execution(void set*(*))“)
public void setterMethod{}

Dadurch wird der Methodenname „setterMethod()“ zu einem ein Aliasname (sog. „Named Pointcut“) für diesen Pointcut. Der Pointcut-Name lautet nun „setterMethod()“ und beschreibt alle Methoden, die den bereits genannten, im Pointcut Ausdruck definierten Kriterien entsprechen. Die Logging Advice Methode trackChange() wird nun mit dem symbolischen Namen (der den Pointcut wesentlich besser beschreibt) als Argument der @Before Annotation versehen:

@Aspect
public class PropertyChangeTracker {
[…]

@Before(„setterMethod()“)
public void trackChange() {
logger.info(„Gleich wird ein Attribut geändert…“);
}
@Pointcut(„execution(void set*(*))“)
public void setterMethod() {}
}

Der Effekt bleibt derselbe: jedesmal, bevor eine Setter-Methode aufgerufen wird, erfolgt die Ausführung der trackChange() Methode. Dabei wird der Aspect auch als „Modul“ bezeichnet, das den CCC „Logging“ wegkapselt.

Jetzt muß der definierte Aspect nur noch per XML Deklaration in den <beans> deklariert werden, um ihn der Spring BeanFactory bekannt zu machen, z.B. durch Import einer „aspects-config.xml“ (für die Aspect-bezogenen Beans Deklarationen) in die eigentliche „application-context.xml“. Damit Spring die @Aspect Annotation auf alle Beans in dieser „application-context.xml“ anwendet, wird innerhalb der „application-config.xml“ noch das Tag <aop:aspectj-autoproxy> mit dem zu registrierenden Aspect eingetragen.

aspects-config.xml:

<beans>
<aop:aspectj-autoproxy>
<aop:include name=“propertyChangeTracker“/>
</aop:aspectj-autoproxy>

<bean id=“propertyChangeTracker“ class=“example.PropertyChangeTracker“/>
</beans>

Dies kann üblicherweise durch import der „aspects-config.xml“ in der „application-context.xml“ erfolgen,
wobei in der größeren äußeren „application-config.xml“ alle Teil-Aspekte zu importieren sind, aus denen
der zu registrierende Aspect besteht und auch weitere in der App verwendete Beans definiert werden.

application-context.xml:

<beans>
<import resource=“aspects-config.xml“/>
<bean id=“…“ class=“…“/>
</beans>

Der Sourcecode der Original Applikation zeigt keinerlei Hinweisauf den Einsatz von AOP, da der nachträgliche Einsatz von AOP für vorhandene Apps völlig transparent bleiben sollte und lediglich den zusätzlichen Import der XML Deklarationen der zusätzlichen AOP-Komponente bedeuten sollte.

Den Application Context für den Zugriff auf die deklarierten Beans und von Spring per BeanFactory (IoC) instanziierten Beans, die anschließend per Dependency Injection (Constructor- oder Setter-basierte Injection DI) an die entsprechenden Beans übergeben werden, holt man sich programmiertechnisch dann folgendermaßen:

ApplicationContext context = new ClassPathXmlApplicationContext(„application-context.xml“);
Bean_Typ bean = (Bean_Typ)Context.getBean(„Deklarierter_Name_der_Bean“);

Übrigens wird man vermutlich bezüglich der Aufrufreihenfolge mehrerer Advice Methoden erwarten, dass diese, je genauer das Argument für die Auflösung des Methodennamens, z.B. in der @Before Annotation ist, umso früher aufgerufen werden, jedoch zeigt sich, dass eine bestimmte Reihenfolge des Aufrufs aller auf einen Pointcut Ausdruck passenden Methoden nicht garantiert werden kann (siehe auch: Best Practices).

Als weiteres Beispiel hier eine Aspect Klasse namens RepositoryTracker, deren logInfo() Methode immer dann aufgerufen werden soll, wenn eine Methode auf dem Interface PersonRepository aufgerufen wird:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class RepositoryTracker {

@Before(„execution(*  de.binaris.springaop.demo.logging.PersonRepository.*(..)“)
public void logInfo() {
System.out.println(„in the logInfo…“);
}
}

Der in diesem Beispiel implementierte Aspect muß dann in der application-config.xml deklariert werden, wobei ein leeres Tag <aop:aspectj-autoproxy /> für die Autodetection aller @Aspects folgendermaßen verwendet wird:

<xml …>
<beans …[…]
xmlns:http://www.springframework.org/aop […]>

<bean   id=“personPrinter“ class=“de.binaris.springaop.demo.PersonPrinterImpl“>
<constructor-arg ref=“personRepository“ />
</bean>

<bean id=“personRepository“ class=“de.binaris.springaop.demo.MockPersonRepository“ />
<bean class=“de.binaris.springaop.demo.logging.RepositoryTracker“ />

<aop:aspectj-autoproxy />
[…]
</beans>

Die gekennzeichneten Platzhalter … enthalten die XML Version und das Encoding (UTF-8), den AOP XML-Namespace (2.5 oder 3.0, beides geht), die spring-aop XML-Schema Lokationen und optional weitere <aop:…> oder <bean>…. Deklarationen.

Weitere Informationen aus dem JoinPoint Objekt erhalten:

Die Advice Methode trackChange(JoinPoint point)wird über ihren „Named JoinPoint“ aufgerufen:

@Aspect
public class PropertyChangeTracker {

[…]
@Before(„setterMethod()“)
public void trackChange(final JoinPoint point) {
String name = point.getSignature().getName();
Object newValue = point.getArgs()[0];
logger.info(„Am Objekt “ + point.getTarget() + “ wird gleich per “ +
“ Methode “ + name + “ folgender Wert gesetzt: “ + newValue);
}

@Pointcut(„execution(void set*(*))“)
public void setterMethod() {}
}

Durch Verwendung des JoinPoint Objekts sind einige nützliche zusätzliche Information erhältlich, denn
ein JoinPoint als Argument einer Advice Methode enthält JoinPoint Context Informationen über den Pointcut und bietet Informationen wie den Namen der aufgerufenen Methode, sowie eine Referenz auf die Argumente, die der Methode übergeben wurden.

Diese Teil-Informationen sind aus Methodenaufrufen auf dem an die Advice Methode übergebenen JoinPoint Objekt erhältlich, wobei sich weder Ziel-Methode, noch die application-config.xmländern. Die einzige Änderung ist, der Signatur der Advice Methode einen JoinPoint Parameter zu geben. Dieser JointPoint wird von Spring’s Bean Factory erzeugt und beim Aufruf an die Advice Methode übergeben, wodurch der Zugriff auf diese JoinPoint Context Informationen ermöglicht wird.

Attributinformationen des JoinPoint Objekts:

„this“: das gegenwärtig ausgeführte Objekt (z.B. der Spring AOP Proxy Wrapper um die
PersonRepositoryImpl Bean)
„target“: die Ziel-Objekt Bean mit der ausgeführten Ziel-Methode, z.B. „findAllByLastname“
„args“: enthält die dem JoinPoint bei Aufruf der Ziel-Methode übergebenen Argumente, z.B. lastName
„signature“: enthält Informationen über die Signatur der Ziel Methode (den Methodenname, die Zugriffs- Modifier, den Rückgabetyp der Methode, etc.)

Einsatz selbstdefinierter Annotationen im Pointcut:

Als nächstes Beispiel soll eine Nachricht nicht vor dem Aufruf jeder Methode geloggt werden, sondern immer vor dem Aufruf einer mit der selbstgeschriebenen Annotation @Tracked gekennzeichneten Convertert-Methode, wobei die selbsterstellte Annotation „Tracked“ im Package demo zu finden ist. Die @Tracked Annotation ist also keine Spring Annotation, sondern selbstdefinierter Teil des Application Models der AOP Applikation:

package de.binaris.springaop.demo;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Self defined annotation to mark Spring AOP target methods
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Tracked {
}

Da die Methode toString () der Klasse „Person“ mit der selbstdefinierten @Tracked Annotation annotiert wurde, wird jedesmal, wenn diese toString() Methode aufgerufenen wird, die Advice Methode namens „logTrackedConversionByJoinpointInfo“ der Klasse „RepositoryTracker“ aufgerufen:

package de.binaris.springaop.demo;

public class Person {

private String firstName;
private String lastName;

public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName  = lastName;
}
[…]

@Tracked
public String toString() {
return lastName + „, “ + firstName;
}
[…]
}

Hier ist die Definition einer Pointcut Expression für eine @Tracked to* Converter Method zu sehen:

package de.binaris.springaop.demo.logging;

@Aspect
public class RepositoryTracker {
[…]
@Before(„trackedConverterMethod()“)
public void logTrackedConversionByJoinpointInfo(final JoinPoint jp) {
String methodName = jp.getSignature().getName();
logger.info(„in the logTrackedConversionByJoinpointInfo()…“);
logger.info(„METHOD: “ + methodName);
}

@Pointcut(„execution(@de.binaris.springaop.demo.Tracked * to*(..))“)
public void trackedConverterMethod() {}
[…]
}

Die Pointcut Expression enthält jetzt also die Annotation @de.binaris.springaop.demo.Tracked,
wofür die @Tracked Annotation im Package de.binaris.springaop.demo ja auch definiert wurde.
Die Pointcut Expression paßt dadurch auf alle Converter Methoden, deren Name mit to* beginnt, die mit der @Tracked Annotation markiert wurden, einen beliebigen Typ zurückgeben und eine beliebige Anzahl Parameter jeweils beliebigen Typs oder auch gar keinen Parameter akzeptieren.

Definition von „execution“ Pointcuts per Pointcut Expression Language (PEL) nach folgendem Muster:

execution(<access modifier>*<return type><package/class name>*.<method name>(
<argument expression>) optional <Exceptions>)

Die komplette AspectJ Expression Language Referenz gibt es unter http://www.eclipse.org/aspectj

Dies ist deshalb so interessant, weil Spring AOP auf AspectJ basiert, somit die Pointcut Expressions auch.

– execution(void send*(String)) : der Ausdruck betrifft alle Methoden, mit Rückgabetyp void
– wenn der Methodenname mit send* beginnt ( z.B. sendMessage, sendTo…, etc. ) und
– die Methode genau einen Parameter vom Typ String akzeptiert

– execution(* send*(int, ..)) : der Ausdruck betrifft alle Methoden, unabhängig vom Rückgabetyp
– wenn der Methodenname mit send* beginnt ( z.B. sendMessage, sendTo…, etc. ) und
– der erste Methoden-Parameter vom Typ int ist, „..“ bedeutet 0 oder mehr Parameter können folgen

– execution(void example.MessageService+.send*(*)) :
der Ausdruck betrifft alle Methoden, mit Rückgabetyp void
– wenn der Methodenname mit send* beginnt ( z.B. sendMessage, sendTo…, etc. ) und
– die Methode genau einen Parameter eines beliebigen Typs akzeptiert und
– die Methode in der das MessageService-Interface implementierenden Klasse liegt oder
in einer implementierenden Klasse eines Subinterfaces or in einer Subclass eines Implementors

– execution(@org.springframework.transaction.annotation.Transactional void *(..)) :
der Ausdruck betrifft alle Methoden, mit Rückgabetyp void
– wenn die Methode mit der @Transactional Annotation markiert wurde und
– die Methode eine beliebige Anzahl an Parametern von jeweils beliebigem Typ akzeptiert und
– die Methode einen beliebigen Namen hat

– execution((@example.Sensible *)*(..)) :
der Ausdruck betrifft alle Methoden, deren Rückgabewert mit der @Sensible Annotation annotiert ist
– und die Methode eine beliebige Anzahl an Parametern von jeweils beliebigem Typ akzeptiert und
– die Methode einen beliebigen Namen hat

– execution(java.lang.Integer *(..)) : der Ausdruck betrifft alle Methoden, vom Rückgabetyp Integer und
– die Methode eine beliebige Anzahl an Parametern von jeweils beliebigem Typ akzeptiert und
– die Methode einen beliebigen Namen hat

– within(*..OrderServiceDefault) && args(order,..): der Ausdruck für die @AfterReturning Annotation
betrifft alle Methoden,
– die in einem beliebigen Package in einer Klasse liegen, die den Namen OrderServiceDefault hat und
– die Methode einen beliebigen Namen hat und
– die Methode einen beliebigen Rückgabetyp hat und
– die Methode eine beliebige Anzahl an Parametern von jeweils beliebigem Typ akzeptiert,
aber der erste Parameter den Namen „order“ haben muß, jedoch von beliebigem Typ sein kann

– pointcut = „within(*..OrderServiceDefault)“, throwing = „ex“: der Ausdruck für die @AfterThrowing Annotation
betrifft alle Methoden,
– die in einem beliebigen Package in einer Klasse liegen, die den Namen OrderServiceDefault hat und
– die Methode einen beliebigen Namen hat und
– die Methode einen beliebigen Rückgabetyp hat und
– die Methode genau einen Parameter namens „ex“ des Default- Typs java.lang.Throwable akzeptiert.

Hier auch der relevante „application-config.xml“ Abschnitt für die Deklaration der @AfterReturning und @AfterThrowing Advice:

<beans>
[…]
<aop:config>
<aop:aspect ref=“orderConfirmation“>
<aop:after-returning
pointcut=“execution(*
de.binaris.springaop.demo.OrderServiceDefault.order(
de.binaris.springaop.demo.domain.Order)) and args(order)“
method=“sendOrderConfirmation“
arg-names=“order“ />
<aop:after-throwing
pointcut=“execution(*
de.binaris.springaop.demo.OrderServiceDefault.order(
de.binaris.springaop.demo.domain.Order))“
throwing=“ex“
method=“noOrderConfirmation“ />
</aop:aspect>
</aop:config>

<aop:aspectj-autoproxy />
</beans>

Seit Spring AOP 2.5 gibt es zusätzlich noch den Bezeichner bean, der die Pointcut Expression auf Beans in der XML Pointcut Definition einschränkt.

Eine @Before Pointcut Expression kann also die folgenden Elemente enthalten:
(value= execution(expression„) and this(myProxyObject) and target(service)       and args(a,…), argNames=a,b)

Eine @AfterReturning Pointcut Expression kann die folgenden Elemente enthalten:
(value= within/execution(expression„) and this(myProxyObject) and target(service)
and args(a,…), argNames=a,b„,returning=returnObject)

Eine @AfterThrowing Pointcut Expression kann die folgenden Elemente enthalten:
(value= within/execution(expression„) and this(myProxyObject) and target(service)
and args(a,…), argNames=a,b„,throwing=myThrowable)

Verwendung voll qualifizierter Package Namen in Pointcut Expressions für:

– Methoden einer bestimmten Klasse/eines bestimmten Interfaces in einem bestimmten Package oder
– Annotationen für die Ziel-Methode oder
– Annotationen für den Rückgabewert/das Rückgabe Objekt einer Methode oder
– einen Rückgabe Objekttyp einer Methode oder
– nicht bereits per import voll qualifiziert deklarierten Typen von Methoden Parametern

Pointcuts können nützliche Joinpoints selektieren, der JoinPoint Context Informationen wegen:

Als Informationen können dabei aus dem JoinPoint Objekt extrahiert werden:

– das aktuell ausgeführte Spring AOP Proxy Object
( PropertyChangeTracker’s Advice Methode „trackChange(…)“ ), oder auch
– das aktuell ausgeführte Ziel Objekt, um daraus die folgenden Informationen zu erhalten
– Ziel-Methodenname: String name = point.getSignature().getName();
– Ziel-Objektname: point.getTarget();
– Ziel-Methodenargumente: point.getArgs()[0];
Annotationen verbunden mit Ziel-Methode, Ziel-Objekt oder Ziel-Methodenargumenten.

@Aspect
public class PropertyChangeTracker {

[…]
@Before(„setterMethod()“)
public void trackChange(final JoinPoint point) {
String name = point.getSignature().getName();
Object newValue = point.getArgs()[0];
logger.info(name + “ wird gleich geändert werden in “ + newValue +
“ auf dem Objekt “ + point.getTarget());
}

@Pointcut(„execution(void set*(*))“)
public void setterMethod() {}
}

Pointcuts:
– sind eine Alternative zur direkten Arbeit mit einem JoinPoint Objekt.
– ermöglichen die Verwendung simpler POJO Advice Methoden
– sind eine weitere alternative Option, um dieselben Informationen zu erhalten, welche über JoinPoints
erhältlich sind

Pointcut Expressions auf typsichere Art verwenden: Pointcut Expression Binding

Im folgenden Beispiel soll eine Log Nachricht jedesmal geschrieben, wenn ein Server gerade starten will, d.h. bevor die start(…) Ziel-Methode ausgeführt wird.

public interface Server {
public void start(Map input);
public void stop();
}

@Before(„execution(void example.Server+.start(java.util.Map))
&& target(server) && args(input)“)
public void logServerStartup(Server server, Map input) {
[…]
}

Die Pointcut Expression betrifft alle Methoden, mit dem Rückgabetyp void und
– die Methode genau einen Parameter vom Typ java.util.Map akzeptiert und
– die Methode im Interface namens Server oder in einer dies implementierenden (Sub-)class liegt.

Diese Pointcut Expressions ermöglichen es, auf typsichere Art Informationen zu erhalten über
die Ziel-Methode „start(…)“ und das Ziel-Methodenargument namens „input“ vom Parametertyp java.util.Map. Indem die JoinPoint Informationen über den jeweiligen Pointcut Ausdruck typsicher an die Logging Advice Methoden Parameter gebunden werden, erhält man dadurch den Parameter namens server vom Typ example.Server und den Parameter namens input vom Typ java.util.Map. Ein expliziter Cast der Advice Methodenargumente aus dem JointPoint auf die Parameter server und input ist somit nicht mehr erforderlich (Typsicherheit mittels Pointcut Expression Binding).

Implementierung der verschiedenen Advice-Arten:

Es gibt also verschiedene Arten von Advice in Form von Annotationen, die nun erklärt werden:
@Before, @After, @AfterReturning, @AfterThrowing, @Around

Before: Der Proxy wird den „BeforeAdvice“ aufrufen, bevor die Ziel-Methode aufgerufen wird.

After:
a) Der Proxy wird den „AfterReturningAdvice“ aufrufen nachdem die Ziel-Methode aufgerufen wurde, die erfolgreich ausgeführt und ohne Exception beendet wurde.
Der AfterReturningAdvice wird nur ausgeführt nach erfolgreicher Ausführung der Ziel-Methode ohne Exception. Wenn die Ziel-Methode jedoch eine Exception ausgelöst hat (Beispiel für eine fehlerhafte Ausführung), wird der AfterReturningAdvice nicht ausgeführt werden.

b) Der Proxy wird den „AfterThrowingAdvice“ aufrufen, nachdem die Ziel-Methode aufgerufen wurde, die eine Exception ausgelöst hat (dies ist das Gegenstück zur AfterReturningAdvice Methode).
Der AfterThrowingAdvice wird nur ausgeführt, wenn die Ziel-Methode eine Exception ausgelöst hat.
Aus diesem Grund bietet sich der AfterThrowingAdvice für standardisierte Exception Verarbeitung an, immer wenn eine Exception ausgelöst wurde und eine Exception-Nachricht geloggt, oder eine E-Mail mit Informationen zur Exception versendet werden soll, wie auch immer das Auftreten einer bestimmten Exception fachlich und technisch behandelt werden soll.

c) Der Proxy wird den „AfterAdvice“ aufrufen, nachdem die Ziel-Methode aufgerufen wurde, unabhängig davon, ob während der Ausführung der Ziel-Methode eine Exception geworfen wurde oder nicht, unabhängig auch davon, ob die Ausführung der Ziel-Methode erfolgreich war oder nicht.

Around: Die Advice Methode wird zuerst ausgeführt und ist verantwortlich für den durch Aufruf von JoinPoint’s proceed() Methode auszulösenden Aufruf der Ziel-Methode.
Die Advice Methode kann selbst einige Logik ausführen, bevor die Ziel-Methode aufgerufen wird.
Dann, nachdem die Ziel-Methode aufgerufen wurde, kann der Advice selbst weitere Logik ausführen.
Der Around Advice ist eine sehr flexible und effektive Advice Methode.
Der Pointcut Ausdruck des “Named Pointcuts“ paßt auf alle Methoden eines beliebigen Rückgabetyps und einer beliebigen Anzahl von Parametern jeweils beliebigen Typs in allen Klassen, die Teil des Service Layers sind. Wenn der Rückgabetyp der JoinPoint Methode „void“ ist, liefert proceed() null zurück.

Der Around Advice kann Werte cachen, die durch den Aufruf von Service Methoden erhalten wurden, wie im nächsten Beispiel gezeigt wird:

Caching als Aspekt (Cross Cutting Concern) und Beispiel für den Around Advice:

package de.binaris.springaop.demo.caching;

import java.util.Map;
import java.util.Hashtable;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;

/**
* The Spring Aop aspect class containing the caching advice with its
*     signatures using the pointcut in the Around annotation and the
*     ProceedingJoinPoint in its method signature to retrieve
*     more detailed info about the objects to be cached.
*/
@Aspect
public class CacheTracker {

private static Map<String, Object> cacheStore =
new Hashtable<String, Object>();

public static Map<String, Object> getCacheStore() {
return cacheStore;
}

private synchronized String cacheKey(final JoinPoint p) {
String key = „“;
if (p.getArgs() != null && p.getArgs().length > 0) {
key = (p.getArgs()[0]).toString();
}
String name = p.getSignature().getName();
return key.isEmpty()? name : name + „_“ + key;
}

@Around(„serviceMethod()“)
public synchronized Object cache(final ProceedingJoinPoint point) {
Object value = cacheStore.get(cacheKey(point));
if (value == null) {
try {
value = point.proceed();
cacheStore.put(cacheKey(point) +
Long.toString((long)value.hashCode()), value);
} catch (Throwable t) {}
}
return value;
}

@Pointcut(„execution(* de.binaris.springaop.demo.PersonRepository.*(..))“)
public void serviceMethod() {}
}

Wenn die Advice Methode „Object cache(ProceedingJoinPoint point)“ aufgerufen wird, sieht sie im „cacheStore“ nach, ob ein Object ihres Parameters „ProceedJoinPoint point“ bereits einmal aufgerufen wurde und verfügbar ist, d.h. ob eine der Ziel-Methoden des „PersonRepository“ Interfaces bereits einmal aufgerufen wurde und es ein dadurch bereits im „cacheStore“ vorhandenes Object gibt.

Wenn nicht, wird point.proceed() auf dem JointPoint aufgerufen, der wiederum durch Aufruf der Ziel-Methode das im „cacheStore“ zu speichernde Ergebnisobject als Rückgabeobjekt hat. Dann wird die Ziel-Methode aufgerufen und was diese Service Methode zurückgibt, wird in der Hashtable namens „cacheStore“ gespeichert, damit, wenn nächstesmal die Advice Methode für diese Ziel-Methode aufgerufen wird, es bereits ein gecachtes Ergebnisobjekt gibt, welches aus dem „cacheStore“ einfach zurückgegeben werden kann, ohne einen aufwändigen (z.B. Webservice- oder Peristenzschicht-)Aufruf der Ziel-Methode immer wieder erneut durchzuführen.

Statische gecachte Daten, die sich nicht ändern, können also nach nur einem Aufruf der Ziel-Methode für den gesamten Lebenszyklus der Applikation verfügbar gemacht werden, solange sie sich nicht ändern. Auf Basis nur eines Ziel-Methodenaufrufs repräsentieren sie dann den korrekten Wert, solange sich der aus dem Persistenz-Layer über die Ziel-Methode erhältliche Wert gegenüber dem über die zugehörige Objekt-Id aus dem Cache erhältlichen Objekt nicht ändert.

Solange sich das Ergebnisobjekt nicht ändert, werden also alle Aufrufe der Ziel-Methode aus dem Cache bedient. Der Aufruf von point.proceed() auf dem JoinPoint erfolgt dagegen nur, wenn das Ergebnisobjekt des Advice-Methodenaufrufs noch nicht gecacht wurde.

Dies ist ein effektives Prinzip, um einen Cache z.B. um einen kompletten Service Layer herum zu implementieren, ohne dass irgendeine Service Komponente Informationen über den Cache haben muß, oder überhaupt von seiner Existenz wissen muß. Die Cache Advice-Methoden sind Teil des Caching Aspects und komplett unabhängig von den Ziel-Methoden des Service Layers und werden vielleicht viel später implementiert als diese Ziel-Methoden, für welche diese modulübergreifenden Funktionalitäten (CCCs) aktiviert werden sollen, ohne die Original-Applikation nachträglich zu ändern.

Um Caching über viele Service Klassen nachträglich zu implementieren, ist AOP also eine Technik und Spring AOP ein geeignetes Framework, um genau dies umzusetzen.

Advice Best Practices:

1) Den einfachsten möglichen Advice verwenden, der funktioniert, um die Komplexität gering zu halten.

2) Möglichst nur wenn absolut erforderlich den @Around Advice verwenden, wenn also wirklich weitere Logik immer VOR UND NACH dem Aufruf der Zielmethode auszuführen ist.

3) Möglichst typsicheres „Pointcut Expression Binding“ verwenden, um explizites Casten auf den Ziel-Objekttyp bei der Übergabe von JoinPoint Context Daten an die Advice Methodenparameter zu vermeiden.

4) „Keep it simple“ (K-I-S), deshalb den einfachsten Implementierungs-Weg wählen, um die Anforderungen umzusetzen. Da Spring AOP die XML Syntax für die Proxy Definitionen,für Aspekte, Pointcuts, Advice etc. anbietet, möglichst die Aspect Logik in Java definieren und die Aspect Konfigurationen in XML.

Deklaration per XML: eine Aspect Definition ohne irgendeine Annotation

a) Aspect Definition mittels Annotation:

@Aspect
public class PropertyChangeTracker {
@Before(„execution(void set*(*))“)
public void trackChange(final JoinPoint point) {
}
[…]
}

b) Aspect Definition mittels XML:

Hierfür wird eine Deklaration der PropertyChangeTracker Bean im application-context.xml benötigt:

<bean id=“propertyChangeTracker“ class=“example.PropertyChangeTracker“ />

Dann kann man den Advice in Spring deklarieren, also Spring bekanntgeben, welche Klasse der Aspect ist und welche Advice Methode innerhalb des Aspects definiert wird.

In den XML Dateien werden die Pointcuts dann durch Verwendung des <aop:pointcut…> Tags definiert.  Diesem Pointcut können ein Property „id“ und ein Property namens „expression“ für die Pointcut Expression gegeben werden. Die „id“ bekommt den Pointcut Namen, auf den die Pointcut Annotation bezogen ist und die „expression“ ist der Pointcut Ausdruck, welcher der @Pointcut Annotation unter Verwendung der Pointcut Expression Language übergeben wird.

Ein Aspect ist nun mit Bezug auf die „propertyChangeTracker“ Bean definierbar. Innerhalb dieses Aspects kann wiederum eine beliebige Anzahl von Advice definiert werden (Before, After, Around):

<aop:config>
<aop:pointcut expression=“execution(void set*(*))“ />
<aop:aspect ref=“propertyChangeTracker“>
<aop:before pointcut-ref=“setterMethod“ method=“trackChange“ />
</aop:aspect>
</aop:config>

In diesem Fall haben wir einen „Before“ Advice definiert. Das Property „pointcut-ref“ zeigt auf die „setterMethod“ der Ziel-Methode, was der „id“-Property des darüber deklarierten <aop:pointcut…> Pointcuts entspricht. Das Property method=“trackChange“ gibt Spring die Information, welche Advice Methode in der „PropertyChangeTracker.class“ ausgeführt werden soll, also welche Advice Methode den Logging bzw. Tracking Advice implementiert.

c) Sicher ist sicher:

Kombinierter Einsatz von XML und Annotationen bei der Definition von Pointcuts am Beispiel:

Mailversand einer „Order Confirmation“:

applicationMail-context.xml:

<?xml version=“1.0″ encoding=“UTF-8″?>
<beans xmlns=“http://www.springframework.org/schema/beans“
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance“
xmlns:aop=“http://www.springframework.org/schema/aop“
xsi:schemaLocation=“http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd“>
<bean id=“retailService“ class=“de.binaris.springaop.demo.MockRetailService“>
</bean>

<bean id=“orderService“ class=“de.binaris.springaop.demo.OrderServiceDefault“>
<property name=“retailService“>
<ref bean=“retailService“ />
</property>
</bean>

<bean id=“mailSender“ class=“org.springframework.mail.javamail.JavaMailSenderImpl“>
<property name=“host“ value=“smtp.yahoo.de“/>
<property name=“username“ value=“mailsender“/>
<property name=“password“ value=“mailsenderPassword“/>
<property name=“javaMailProperties“ value=“mail.smtp.auth=true“ />
</bean>

<bean id=“message“ class=“org.springframework.mail.SimpleMailMessage“>
<property name=“from“ value=“orderconfimations_by_springaop@yahoo.de“/>
<property name=“to“ value=“orderconfimations_by_springaop@yahoo.de“/>
<property name=“subject“ value=“Order Confirmation“/>
</bean>

<bean id=“orderConfirmation“ class=“de.binaris.springaop.demo.mail.OrderConfirmation“>
<property name=“mailSender“ ref=“mailSender“/>
<property name=“message“ ref=“message“/>
</bean>

<aop:config>
<aop:aspect ref=“orderConfirmation“>
<aop:after-returning
pointcut=“execution(*
de.binaris.springaop.demo.OrderServiceDefault.order(
de.binaris.springaop.demo.domain.Order)) and args(order)“
method=“sendOrderConfirmation“
arg-names=“order“ />
<aop:after-throwing
pointcut=“execution(*
de.binaris.springaop.demo.OrderServiceDefault.order(
de.binaris.springaop.demo.domain.Order))“
throwing=“ex“
method=“noOrderConfirmation“ />
</aop:aspect>
</aop:config>
</beans>

OrderConfirmation.java (Aspect):

 

package de.binaris.springaop.demo.mail;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;

import de.binaris.springaop.demo.domain.Order;
import de.binaris.springaop.demo.OrderServiceDefault;

@Aspect
public class OrderConfirmation implements IOrderConfirmation
{
Log logger = LogFactory.getLog(getClass());

private MailSender mailSender;
private SimpleMailMessage message;

public void setMailSender(MailSender mailSender)
{
this.mailSender = mailSender;
logger.info(„this.mailsender: “ + this.mailSender);
}

public void setMessage(SimpleMailMessage message)
{
this.message = message;
}

@AfterReturning(„within(*..OrderServiceDefault) && args(order,..)“)
public void sendOrderConfirmation(Order order)
{
// send order confirmation
SimpleMailMessage simpleMailMessage = new SimpleMailMessage(message);
// use parameters from, to und subject defined in
// applicationMail-context.xml
simpleMailMessage.setText(„Thank you very much for your order.“);

try
{
mailSender.send(simpleMailMessage);
logger.info(„Order confirmation has been sent successfully.“);
} catch (MailException ex)
{
logger.error(„Error with sending order confirmation: “ +
ex.getMessage());
}
}

@AfterThrowing(pointcut = „within(*..OrderServiceDefault)“, throwing = „ex“)
public void noOrderConfirmation(Exception ex)
{
// no order confirmation will been sent
logger.warn(„No order confirmation has been sent due to this + „exception: “ + ex.getMessage());
}
}

Eine kurze Zusammenfassung zum Thema Spring AOP könnte die folgende Fakten wiederholen:

– Spring AOP dient der Modularisierung modulübergreifender Funktionalitäten (CCCs), die sich als dynamische Proxies in jede bestehende Applikation einklinken lassen, ohne die Applikation ändern und neu compilieren zu müssen.

– In Spring AOP werden Aspects als POJOs (Plain Old Java Classes) geschrieben und mit der @Aspect Annotation annotiert oder als Aspects in der application-context.xml definiert.

– Innerhalb dieser Aspekte werden Advice Methoden definiert, die als folgende Advice annotierbar sind: Before, After, Around, AfterReturningAdvice und AfterThrowingAdvice

– Pointcuts bestimmen die Auswahl, wo eine Advice Methode matcht und wann diese aufgerufen wird.

Deklarative Transaktionsmanager und Transaktionen als Aspekte in Spring AOP:

(Diese werden in einem gesonderten Blog Eintrag besprochen.)

Testen von Spring AOP Anwendungen und Aspekten:

Das sehr empfehlenswerte „Spring Praxishandbuch“ aus dem entwickler.press Verlag nennt unter anderem folgende wichtige Punkte zur Vermeidung von Komplikationen beim Testen von Spring AOP und AspectJ Anwendungen:

Möglichst genaue Definition der Pointcuts, damit diese nicht auf zu viele oder zu wenige Methoden   zutreffen, sondern genau auf diejenigen auf die ein Pointcut im Test zutreffen soll.

– Weiterhin die Berücksichtigung von Abhängigkeiten zwischen den Advice Methoden und deren Ausführungsreihenfolge, denn die falsche Reihenfolge kann bei der Ausführung die Testergebnisse verfälschen, oder deren Nutzen gänzlich in Frage stellen.

– Zu Verhindern sind auch ungewollte Effekte, wenn eine unbeteiligte neue Methode durch Deklaration im falschen Package ungewollt auf einen Pointcut zutrifft und beim Testen zu einem JoinPoint wird, weshalb die Package Definitionen für die Aspekte möglichst signifikant und detailiert sein sollten.

– Zur Sicherstellung der korrekten Basis Funktionalitäten von Aspekten sollte deren Funktionalität mittels Delegate Pattern z.B. in Helper Klassen ausgelagert werden, um diese gesondert per Unit-Tests auszutesten, bevor die integrativen Tests der eigentlichen Cross Cutting Concerns (CCCs) der Aspekte durchgeführt werden, bei denen dann wiederum möglichst viele Aspekte ineinandergreifend mit stufenweise zunehmender Komplexität getestet werden sollten.

Weitere empfehlenswerte Bücher sind „Spring 2.5“ aus dem ADDISON-WESLEY Verlag, das Buch von Eberhard Wolff mit dem Titel „Spring 3“aus dem dpunkt Verlag, das Buch „SPRING im Einsatz“ von Craig Walls aus dem HANSER Verlag, sowie das Buch „springframework 2“ aus dem WROX Verlag, um nur einige zu nennen.

Dieser Artikel hat als Quelle Beispielcodes aus dem offiziell, frei verfügbaren Quick Time Movie „s2university_aop2.mov“ und Informationen aus den genannten Büchern als auch eigene Erfahrungen mit dem Spring AOP Framework zur Grundlage.

Kommentare

9 Kommentare zu “Aspekte auslagern – mit Spring AOP und AspectJ”

  1. Von Service Architekturen – mit Spring und Hibernate : binaris informatik GmbH am Sonntag, 21. August 2011 17:19

    […] erstmal nichts hinzuzufügen. Zur Erklärung des Einsatzes von AOP wird auf bereits existierende Einträge in diesem Blog zum Thema AOP verwiesen. Ebenso wird zur Erklärung des Einsatzes von Spring und Hibernate auf bereits […]

  2. Von Web Applikationen – Selbstdefinierte Annotationen mit Spring : binaris informatik GmbH am Sonntag, 29. April 2012 11:59

    […] der eigentlichen Anwendung und der annotierten Klassen bzw. deren Methoden und Attribute. Über den Einsatz von Annotationen in Spring für Aspects, Join Points u. Pointcuts mit AspectJ gibt es bereits einen Blog-Eintrag in diesem Blog, weil Annotations auch dafür sehr […]

  3. Von Web Applikationen – Spring MVC mit Selenium u. AOP testen : binaris informatik GmbH am Dienstag, 22. Mai 2012 18:51

    […] AOP Einsatz mit Spring gibt es bereits einen Eintrag in diesem Blog mit dem Titel “Aspekte auslagern – mit Spring AOP und AspectJ“, weshalb sich dieser aktuelle Blog Eintrag an Java/JEE Entwickler mit Spring und AOP Kenntnissen […]

  4. Von sven am Mittwoch, 18. Juli 2012 10:57

    Moin,

    ich bin gerade über diesen interessanten Artikel gestossen. Ich stehe vor der Problematik, dass Probleme beim Refactoring der Packages, Klassen oder Methoden die Advises nicht mehr funktionieren. Was ist hier „Best Practise“, um dies zu verhindern?

    Gruß,
    Sven

  5. Von ukrull am Donnerstag, 19. Juli 2012 20:58

    Hi Sven,

    z.B. durch Annotierung mittels @Before- oder @After-Annotation auf Methodenebene,
    anstatt vollqualifizierte Packagenamen zu verwenden, d.h. entweder

    a) der JoinPoint zielt auf die Ausführung einer Methode:

    @Before(“execution(void set*(*))”)

    oder
    b) der Pointcut zielt auf die Ausführung einer Methode:

    @Pointcut(“execution(void set*(*))”)
    public void setterMethod() {}
    }
    @Before(“setterMethod()”)
    public void trackChange() {
    logger.info(“Gleich wird ein Attribut geändert …”);
    }

    Die „Best Practices“ bestimmen sich durch den Anwendungsfall.
    Auch hierbei gilt: „Konvention geht vor Konfiguration“.

    Viele Grüsse
    Uwe

  6. Von Architekturen – Design Patterns und Technologien : binaris informatik GmbH am Dienstag, 24. Juli 2012 18:03

    […] Ein Bespiel, bei dem für Architekten, Designer oder Entwickler die Auswahl der verwendeten Technologien und Design Patterns nicht automatisch vorgegeben wird, z.B. in Abhängigkeit vom verwendeten Transaktionstyp (JTA, RESOURCE_LOCAL), ist der Zugriff auf zwei Datenbank-Kataloge innerhalb derselben Applikation, hier ein Beispiel dazu unter Verwendung von Spring Roo mit zwei TransaktionsManagern und AspectJ. […]

  7. Von Eclipse RCP – OSGi, Equinox und SOA : binaris informatik GmbH am Sonntag, 30. September 2012 13:34

    […] Das Spring Framework kümmert sich um die ganze Dynamik des Systems. Im rein programmatischen Ansatz muss z.B. auf benötigte Services gewartet werden, falls diese gerade nicht verfügbar sind. Durch die Verwendung von AOP Proxys, werden diese durch den Container zur Verfügung gestellt, wodurch der Code klarer und auch lesbarer wird. Über AOP-Proxies bei der Verwendung von Spring und AspectJ gibt es bereits einen Eintrag in diesem Blog. […]

  8. Von Projekte generieren – mit Spring Roo und AspectJ : binaris informatik GmbH am Sonntag, 27. Januar 2013 20:31

    […] Spring AOP und AspectJ gibt es hier bereits einen Artikel in diesem […]

  9. Von Architekturen – mit Spring CDI, JPA, JBoss, JavaEE : binaris informatik GmbH am Dienstag, 1. Juli 2014 22:28

    […] Wenn in Spring die @ApplicationScoped AuthorizationBean unter Verwendung der @SessionScoped UserCredentialsBean erzeugt wird, ist die injectete Instanz wegen des in Spring implizit verwendeten Singleton Patterns für die gesamte Lebensdauer der Consumer Bean dieselbe UserCredentialsBean. Dieselbe UserCredentialsBean wird also für alle Aufrufe innerhalb der AuthorizationBean verwendet, weshalb die AuthorizationBean mittels AOP-Annotationen (AspectJ, SpringAOP) als “Dynamischer  Proxy” mit entsprechenden JoinPoints und Pointcuts verwendet werden sollte, entweder innerhalb der Spring Configuration oder mittels Annotationen auf den entsprechenden Klassen. Hierüber gibt es bereits einen Blog-Eintrag in diesem Blog hier. […]

Einen Kommentar hinzufügen...

Sie müssen registriert und angemeldet sein um einen Kommentar zu schreiben.