Einführung: AOP / Aspektorientierte Programmierung

In diesem Artikel wird die aspektorientierte Programmierung, kurz AOP genannt, einführend erläutert. Als Grundlage dient das Buch „AspectJ in Action von Ramivas Laddad, das sowohl eine theoretische Einführung in die AOP enthält als auch einige praktische Beispiele vorstellt.


Dies Einführung in die AOP findet in den ersten vier Kapiteln statt:

  • In dem ersten Kapitel wird die Geschichte der AOP und das Umfeld, aus dem AOP entstanden ist umrissen.

  • Das zweite Kapitel beschäftigt sich mit der theoretischen Einführung in die AOP.

  • Im dritten Kapitel wird eine Implementierung der AOP an dem Beispiel von AspectJ vorgestellt.

  • Abschließend wird im vierten Kapitel die praktische Anwendung von AspektJ gezeigt (noch nicht online)

Ziel dieser Ausarbeitung ist es, das Grundverständnis für AOP und einen praktischen Einblick in die Arbeit mit AOP zu vermitteln.

Die Entstehung der aspektorientierten Programmierung

Diese Seminararbeit entsteht zu einem Zeitpunkt, an dem die AOP kein theoretischer Ansatz mehr ist. Sie wird heute bereits produktiv eingesetzt. Das Umfeld reicht von Literatur sowohl zur Methodologie als auch zu Implementierungen bis hin zu Referenzprojekten.

Historische Entwicklung

Der Begriff AOP wurde erstmals 1996 in Veröffentlichungen von Gregor Kiczales im Palo Alto Research Center, von Xerox Corporation erwähnt. Das Team hinter Gregor Kiczales und Cristina Lopes waren die ursprüngliche Entwickler von AspectJ.

Die Grundidee hinter AOP hat sich aus der frühen Erkenntnis heraus kristallisiert, dass wartbare Systeme erst durch die strikte Trennung ihrer Dienste zu implementieren sind. Diese Erkenntnis wurde Separation of Concerns, kurz SOC, getauft. Bereits 1972 wurde in einem Artikel1 von David Parnas [L6] festgehalten, dass Modularisierung und Kapselung der beste Weg für das Erreichen von SOC sei. Beschrieben wurde die Modularisierung als ein Prozess, in dem Dienste in Modulen implementiert werden. Diese Module haben Ihre Implementierung voreinander gekapselt.

Die Evolution der Softwareentwicklung hat viele Techniken und Frameworks zum Erreichen von SOC hervorgebracht. Allen gemeinsam ist das Ziel, komplexe Systeme wartbarer zu machen.

Das Umfeld

Die Entwicklung komplexer Systeme stellt besondere Herausforderungen an die Entwickler. Neben der eigentlichen Geschäftslogik (engl. „core concerns“), auch fachliche Anforderungen genannt, müssen systemtechnische Crosscutting Concerns wie Authentifizierung, Persistenz, verteilte Kommunikation, transaktionales Verhalten und Protokollierung implementiert werden.Das Modell der Geschäftslogik wird in vielen Projekten heute in dem objektorientierten Ansatz entwickelt, da es der menschlichen Denkweise am nächsten liegt: in der objektorientierten Softwareentwicklung werden, vereinfacht dargestellt, Systeme als Ansammlung zusammenarbeitender Objekte modelliert. Objekte besitzen einen Zustand und ein Verhalten, das ihrer Klasse definiert und implementiert wird.Durch diese Vorgehensweise, den Einsatz von Entwurfsmustern [L2] und sogenannten Refactoring-Techniken [L3] sollte ein besonders hohes Maß an Wiederverwendbarkeit einzelner Komponenten erreicht werden. Das Versprechen der Wiederverwendbarkeit lässt sich häufig nicht einlösen, da speziell auf der Ebene der Programmierung oftmals nichtfachliche beziehungsweise technische Anforderungen nicht vollständig in separaten Klassen kapseln lassen. Statt dessen durchziehen solche Aspekte eines Softwaresystems in nicht unerheblichem Ausmaß den rein fachbezogenen Teil der Implementierung. Dies führt dazu, dass Klassen zu konkret an einen Einsatzkontext gebunden und nicht mehr beliebig wiederverwendbar sind.

Die nichtfachlichen, beziehungsweise technischen Anforderungen werden in der Literatur zu aspektorientierter Programmierung als Crosscutting Concerns bezeichnet.

Technische Anforderungen sind integraler Bestandteil komplexer Software­systeme und nicht wegzudenken. Aus diesem Grund werden Design­entscheidungen oftmals von fachfremden Anforderungen beeinflusst.

Oft ist es nicht absehbar, welche Dienste in welcher Form in einem System benötigt werden. Da Crosscutting Concerns naturbedingt nicht nur in einem Modul, sondern zusätzlich in den Fachklassen zumindest aufgerufen werden, haben Veränderungen in diesem Bereich kritische Auswirkungen auf das gesamte System.

Speziell für den Entwurf transaktionaler, verteilter, sicherer, unternehmens­kritischer Anwendungen wurde das Framework Enterprise JavaBeans, kurz EJB, von Sun entwickelt. In einem Applikationsserver werden Crosscutting Concerns wie Sicherheit, Persistenz, transaktionales Verhalten, Clustering und Ausfallsicherheit für die so genannten enterprise beans von einer EJB-Laufzeitumgebung (EJB container) bereitgestellt. In welchem Umfang und Konfiguration diese Dienste verwendet werden, wird über eine XML-Konfigurationsdatei (engl. „deployment descriptor?) definiert. Die EJB-Laufzeit­umgebung, die alle Komponenten und deren XML-Konfigurationen kennt, stellt diese Crosscutting Concerns bereit. Damit das funktionieren kann, verliert der Entwickler die Kontrolle über den Lebenszyklus der eigenen Komponenten und darf lediglich Dienste, bzw. Schnittstellen bereitstellen. Alle Aufrufe auf die Komponenten werden von der Laufzeitumgebung abgefangen. Die Anzahl der Restriktionen ist hoch; das Framework ist speziell für den Entwurf von Client-Server-Anwendungen in einem sehr engem Rahmen erstellt worden.

Das EJB-Framework zeigt,

  • dass es nicht trivial ist, das Design der eigenen Fachlogik mit den Anforderungen des technischen Rahmenwerkes zu vereinen bzw. getrennt zu entwickeln, und

  • dass ein solches Framework sehr umfangreich werden kann

Projekte, die heute nicht in das Raster von Enterprise JavaBeans passen, oder vielleicht nicht in Java entwickelt werden sollen, werden sofort wieder mit der Problematik der Crosscutting Concerns und der Entwicklung eines passenden Frameworks konfrontiert.

public class MeineGeschäftslogik {
… geschäftlogik Attribute
… protokollierungs-API Attribute
… cache update Status

public void loeseAufgabe( Aufgabe-Parameter, Authentifikationsdaten)
{
… Authentifizierung sicherstellen
… Objektsperre setzen
… start protokollieren
geschäftslogik
… persistenz ausführen
… ende protokollieren
… Sperre aufheben
}
}

Beispiel 1″Code Tangling”

An dem oberen Beispiel wird anschaulich dargestellt, wie die Crosscutting Concerns, obwohl in externen Modulen implementiert, in der Geschäftlogik wieder auftauchen. Diese Crosscutting Concerns sind ohne das Erstellen eines entsprechenden Frameworks nicht aus dem Programmcode wegzudenken.

Die Folgen sind Verminderung der Softwarequalitätsmerkmale Lesbarkeit, Wiederverwendbarkeit, Wartbarkeit und Änderbarkeit. In dem Buch von Ramnivas Laddad [L1] werden in diesem Kontext zwei Phänomene erwähnt: Code Tangling und Code Scattering. Die folgende Grafik skizziert in abstrakter Form ein System, das solche Phänomene aufweisst. Komponenten werden durch die einzelne Puzzlesteine repräsentiert:

abbildung1-klein.png
Abbildung 1

Der Begriff Code Tangling beschreibt die in Beispiel 1 dargestellte Vermengung von Core Concerns und Crosscutting Concerns. In der Abbildung 1 wird dieses Phänomen in den Komponenten der fachlichen Anforderungen gezeigt.

Unter Code Scattering versteht man die Streuung der Implementierung eines Dienstes in mehreren Modulen. In der Abbildung 1 wird deutlich gezeigt, dass die Aspekte Logging und Authentifizierung sowohl in eigene Komponenten als auch in aspektfremde Komponenten implementiert werden.

Während Code Tangling negative Auswirkung auf die Software-qualitäts­merkmale Lesbarkeit und Wiederverwendbarkeit hat, führt Code Scattering zu Verschlechterung in der Wartbarkeit und Änderbarkeit des Systems.

Mythos AOP

Die aspektorientierte Programmierung wird heute nach der Einführung der objektorientierten Programmierung, kurz OOP, als weiterer Paradigmen­wechsel behandelt. Man muss jedoch beachten, das AOP kein neues Paradigma in der Modellierung darstellt. Lediglich in der Implementierung stellt sich aspektorientierte Programmierung als Erneuerung dar.

Diese Erneuerung ist nicht unwesentlich: dadurch entstand fälschlicherweise der Eindruck, dass durch den Einsatz von aspektorientierter Programmierung die objektorientierte Programmierung ersetzt werde. Dieser Mythos entstand aus dem Unwissen, welche Vorteile und Neuerungen die AOP tatsächlich für die Softwareentwicklung mit sich bringt.

Vor einiger Zeit hat das „Unit Testing“, insbesondere durch den breiten Einsatz von jUnit, in der Java-Gemeinde für Aufsehen gesorgt. Es wurde schnell akzeptiert, dass das automatisierte und atomare Testen sehr positive Auswirkungen auf den Entwicklungsprozess haben kann. In diesem Umfeld entstand der Begriff der „Continuous Integration“ in einem Dokument von Martin Fowler.

Bestehende Projekte haben festgestellt, dass schlecht entwickelte Komponenten schwierig zu testen sind. Die Testbarkeit von Komponenten hat sich sogar als Indiz für die Designqualität des Codes entwickelt. Mittel- und kurzfristig wurden als Folge zur Einführung des Unit-Testings Komponenten entwickelt, die kleinste kohärente und sinnvolle Funktionalität abgebildet haben, und somit einfacher zu testen waren. Testbarkeit, Wiederver­wendbarkeit und Änderbarkeit sind erkärte Ziele eines jeden Software­projektes, das erfolgreich sein will. Die grösste Problematik stellen die Crosscutting Concerns dar.

Sicherlich kann man die aspektorientierte Programmierung als nächsten Schritt in der Evolution der Softwareentwicklung betrachten. Schliesslich kommen wir mit dieser Technik dem Ziel deutlich näher, Dienste – egal welcher Natur – in eigene Module zu kapseln. Allerdings ist AOP kein Wundermittel gegen schlechtes Design, eher ein Vitamin, das die Software­entwicklung effizienter machen kann.

Einführung in die aspektorientierte Programmierung

Die Idee hinter der aspektorientierten Programmierung besteht darin, die so genannten Crosscutting Concerns komplett in eigene Komponenten auszulagern. Diese werden schliesslich Aspekte genannt. Dadurch wird die ursprüngliche Fachlogik nicht mehr um die orthogonale Funktionalität aufgebläht.

Aspektspezifische Anweisungen

Eine echte Trennung von Diensten auf der Ebene der Programmierung läßt sich durch Auslagern aspektspezifischer Anweisungen in eigenständige Entitäten erreichen.

Ein solchermaßen aspektorientiert entwickeltes Softwaresystem besteht aus herkömmlichen Klassen, die die fachlichen Anforderungen implementieren, und – als neues Modularisierungskonzept – aus Aspekten, die jeweils eine bestimmte technische Anforderung realisieren.

Aspekte wirken dabei auf Klassen ein, indem sie deren Methoden um zusätzliche Anforderugen erweitern. Sie ergänzen somit das Verhalten von Objekten um aspektspezifische Anteile, ohne dabei das fachliche Verhalten zu beeinflussen.

Wie in jeder neuen Methodologie oder Technik gibt es auch für die AOP ein „Hello World“: hier verwendet man in der AOP-Literatur die technische Anforderung des Protokollierens (Logging, Tracing) um ein entsprechend anschauliches Beispiel aufzusetzen.

Die Protokollierung bildet ein Aspekt des Systems, und die Fachklassen werden frei vom Protokollierungscode entwickelt.

Allgemeine Vorgehensweise

Die Entwicklung einer AOP Software verläuft im wesentlichen nicht anders als bei der OOP: zunächst werden die Anforderungen ermittelt und implementiert. Die Integration aller entwickelten Komponenten bildet schließlich das Gesamtsystem.

Analog werden in der aspektorientierten Programmierung drei Entwicklungsphasen beschrieben:

  • Aspect Decomposition

  • Concern Implementation

  • Aspectual Recomposition

In der folgenden Abbildungen werden die einzelnen Phasen gezeigt. Die Zerlegung der Anforderungen in Aspekte und das Weben (engl. „weaving?) der Aspekte zu einem Endsystem wird metaphorisch dargestellt.

abbildung2-klein.png
Abbildung 2

Erste Phase: Aspectual Decomposition

In dieser Phase findet die Zerlegung der Anforderungen in die einzelnen Aspekte des Systems statt. Ausgangspunkt sind die an das System gestellten Anforderungen, sowohl die fachlichen als auch die technischen. Die Modellierungsmethodik wird von der aspektorientierten Programmierung nicht vorgeschrieben. Das Zerlegen in einzelne Aspekte wird in der Abbildung 2 durch den concern identifier dargestellt.

Zweite Phase: Concern Implementation

Sobald die Anforderungen in eine Menge von Aspekten zerlegt worden sind, werden diese unabhängig voneinander implementiert. Mit unabhängig ist gemeint, dass die jeweilige Implementierung eines Aspektes kein Wissen über und keinen Zugriff auf andere Aspekte besitzt. So lassen sich die fachlichen Anforderungen definitiv ohne Einwirkung von technischen Aspekten entwickeln. Selbstverständlich sind auch die technischen Anforderungen ohne Einfluss der Fachlogik implementiert. Diese Tatsache führt dazu, dass diese Komponenten wiederverwendbar entwickelt werden können.

Dritte Phase: Aspectual Recomposition

In der letzten Phase werden die Regeln für die Verwebung der einzelnen Aspekte erstellt. Diese Regeln legen die Zusammenarbeit bestimmter Komponenten fest. Der Entwickler definiert nur die Regeln, das zusammengesetzte System wird von der Entwicklungsumgebung erstellt. Diese Tätigkeit wird in der Abbildung 2 durch den Weaver dargestellt.

Anatomie der AOP

Es ist zu beachten, dass AOP keine Implementierung sondern lediglich eine Methodologie darstellt. Analog ist die objektorientierte Programmierung eine Methodologie und Java und Smalltalk sind bekannte Realisierungen.

Eine Realisierung umfasst die Definition der Sprachelemente, der Syntax und das Bereitstellen der benötigten Tools, wie zum Beispiel einen Compiler.

Somit wird von einer AOP Implementierung eine Sprachdefinition und die entsprechende Implementierung erwartet.

Die AOP Sprachdefinition

Eine für die AOP geeignete Sprachdefinition muss folgende zwei Kern­bereiche festlegen. Diese werden in der Literatur „Implementation of concerns“ und „Weaving rules specification“ genannt.

  • Implementation of concerns:

    Die Sprache, mit der die Komponenten entwickelt werden, da die Hauptaufgabe schließlich nach wie vor die Implementierung der einzelnen Komponenten ist.

    Üblicherweise verwenden AOP Realisierungen an dieser Stelle bestehende Programmiersprachen, wie Java, C++, und Python.

  • Weaving rules specification:

    An dieser Stelle werden die Sprachelemente für das Integrieren der Aspekte definiert. Die Stärke einer AOP Realisierung zeigt sich darin, wie ökonomisch diese Integration beschrieben werden kann.

Ziele

Die Realisierung einer AOP Sprache muss folgende Arbeit leisten: zuerst müssen die einzelnen Aspekte mittels der definierten Integrationsregeln (engl. „weaving rules“) vermengt werden, und schließlich daraus ausführbarer Code, das Endsystem, generiert werden.

abbildung3-klein.png
Abbildung 3

Die Abbildung 3 zeigt eine Skizze einer allgemeinen AOP Realisierung. Im Vergleich zu Abbildung 1 sind die einzelnen Komponenten absichtlich einfarbig dargestellt. Die Komponenten werden erst im Endsystem miteinander verwoben.

Üblicherweise werden die Integrationsregeln in eigenen Entitäten abgelegt, wie in Abbildung 3 dargestellt. Der AOP-Compiler, auch weaver genannt, nutzt diese Regeln um das Verhalten des Endsystems zu realisieren, in dem die einzelnen Aspekte entsprechend verwoben werden.

Die Auslagerung der Integrationsregeln in eigene Entitäten ist wichtig. So ist es möglich, zusätzliche Integrationsregeln in das Endsystem einzuflechten, ohne bestehenden Code zu verändern.

Technische und fachliche Aspekte greifen ineinander über: Das Ergebnis ist wieder verwoben. Dieses Problem wird von der AOP nicht gelöst. Es wird lediglich ein besserer Weg zum gleichen Ziel eingeschlagen. Besser in dem Sinn, dass die AOP versuchen will, endlich das Versprechen der objekt­orientierten Methodologie einzulösen: die einzelnen Bausteine eines Systems sollen wartbar und wiederverwendbar sein.

Implementierungen

Die aspektorientierte Programmierung stellt eine Methodologie , aber keine Implementierung dar. Je nach Programmiersprache und Umgebung sind unterschiedliche Implementierungen entstanden.

Die in dieser Seminararbeit verwendete AOP-Implementierung nennt sich AspectJ. Diese wurde von einem Team aus dem Palo Alto Research Center, von Xerox Corporation, dem Eclipse Konsortium gespendet. Die aktuelle Version trägt die Bezeichung AspectJ Version 1.2.

Der Vollständigkeit halber sollen hier noch weitere Implementierungen aufgezählt werden:

AspectC++

http://www.aspectc.org

ist eine Implementierung für die Programmiersprache C++.

AspectWerkz

http://aspectwerkz.codehaus.org

Eine weitere AOP Implementierung für Java. Interessant an dieser Lösung ist, dass das Verweben zur Laufzeit stattfindet.

AspectXML

http://www.aspectxml.org

Dieses Projekt realisiert die AOP Ansätze auf XML Dokumente.

AspectPerl

http://search.cpan.org/~marcel/Aspect-0.08/lib/Aspect/README.pod

Ein Perl- Modul, das AOP für die Perl- Skriptsprache implementiert.

Aspects

http://www.logilab.org/projects/aspects/

Eine AOP Implementierung für Python.

Quelle: http://www.aosd.net

AspectJ: Eine Implementierung von AOP für Java

Die AOP Implementierung AspectJ bietet Java-Entwicklern eine Erweiterung der Java-Programmiersprache. AspectJ ist OpenSource und unter der Mozilla Public License Version 1.1 erhältlich. Plugins für Entwicklungsumgebungen wie Eclipse, Netbeans und JBuilder sind erhältlich.

Mit AspectJ bekommt man eine Dokumentation und Tools wie einen Compiler, einen Aspekte Browser und eine erweiterte Version des Tools Javadoc, dass mit Aspekten umgehen kann. In der mitgeliefertern Doku­mentation befinden sich unter anderem Installationsanleitungen, Referenzen für die Sprach- Erweiterungen und einige Beispiele.Die Plugins für Ent­wicklungsumgebungen müssen separat bezogen werden.

Die Beigabe der Aspektorientierung erfolgt über die Erweiterung des Java-Sprachumfangs um AOP-Elemente, unter anderem das einer Klasse nicht unähnliche Konstrukt aspect. Neben den bekannten Methoden und Attributen definiert ein Aspekt pointcuts und advices.

Grundsätzlich unterscheidet AspectJ zwischen Dynamic Crosscutting und Static Crosscutting.

Bei Dynamic Crosscutting geht es darum, dass die definierten aspekt­spezifischen Methoden das Laufzeitverhalten (dynamisches Verhalten) modifiziert. Im Gegensatz dazu verändert Static Crosscutting die statische Struktur des Programmcodes.

Join Points und Pointcuts

Join Points sind addressierbare Punkte im Quelltext. Beispiele für Join Points sind Methodenaufrufe oder Zugriffe auf Attribute.

public class Dose {
private boolean istOffen = false;
public void oeffnen()
{
istOffen = true;
}
}

Beispiel 2 Beispiel für Pointcuts und Join Points

In obigen Beispiel sind u.a. folgende Join Points zu finden:

  • die Ausführung der Methode „oeffnen()

  • der schreibende Zugriff auf das Attribut „istOffen

Unter Pointcut versteht man schließlich die Addressierung eines oder mehrerer Join Points.

Die zwei oben genannten Join Points könnten durch folgende Pointcuts addressiert werden:

  • execution( void Dose.oeffnen() )

  • set( private boolean Dose.istOffen )

Join Points sind lediglich Bezeichnungen für addressierbare Punkte im Quelltext, während Pointcuts die tatsächlichen addressierten Punkte darstellen.

Bei der Definition von Pointcuts werden Sprachelemente verwendet, die nicht zum Sprachumfang der Java-Programmiersprache gehören.In der Definition von Pointcuts können auch folgende Platzhalter eingesetzt werden:

„ .. “ für beliebig viele Zeichen

„ * “ für beliebig viele Zeichen ausser einem Punkt

„ + “ für beliebige Spezialisierungen einer Klasse oder eines Interfaces

AspectJ bietet ein umfangreiches dynamisches Join Point Modell. Die folgenden Beispiele sollen im Groben einen Eindruck über den Umfang vermitteln.


Das Ausführen einer Methode:

execution( void Dose.oeffnen() )
execution( int *() )

Das Aufrufen einer Methode:

call( void Dose.oeffnen() )
call( * *( long ) )

Das Catchen bzw. Behandeln einer Exception:

handler( RemoteException )
handler( RuntimeException+ )

Der Ausführende eines bestimmten Typs ist:

this( Dose )

Der Aufgerufene eines bestimmten Typs ist:

target( Dose )

Der ausgefürte Code eines bestimmten Typs ist:

within( meine.servlets.* )

Der ausgeführte Code, der von einer bestimmten Methode
aufgerufen wurde (engl. „call flow“) – inklusive oder
exclusive der aufrufende Methode:

cflow( Dose.oeffnen() )
cflowbelow( Dose.oeffnen() )

Initialisierung eines Objekts:

initialization( Dose.new(..) )

Aufruf der Konstruktors „super“ eines Objektes:

preinitialization( Dose.new(..) )

Wenn der Klassenkonstruktor aufgerufen wird:

staticinitialization( Dose )

Das Lesen oder Schreiben von Instanzattribute:

get( Dose.istOffen )
set( Dose.istOffen )

Advices

Advices definieren die aspektspezifischen Code-Erweiterungen. Advices beziehen sich auf Pointcuts und werden an den entsprechenden Stellen durch den AOP Compiler hinzugefügt.

Die Syntax eines Advices ähnelt sehr der Syntax eines Methodenaufrufs. Der Unterschied besteht lediglich darin, dass ein Advice noch definieren muss, wann dieser Code ausgeführt werden soll:

  • before: vor dem definiertem Pointcut,

  • after: nach dem definiertem Pointcut oder

  • around: um den Pointcut herum.

Somit kann der Entwickler vor dem Aufruf der Methode „void oeffnen()“ ein zusätzliches Verhalten implementieren:

Innerhalb eines Advices werden die impliziten Variablen

  • thisJoinPoint

  • thisJoinPointStaticPart

  • thisEnclosingJoinPointStaticPart

dem Entwickler zur Verfügung gestellt. Somit bekommt der Entwickler dynamisch Zugriff auf dem Kontext der aus dem entsprechendem Pointcut entstanden ist. Die Kontextinformationen basieren auf der Java-Reflection API, so dass der Entwickler sich nicht in ein neues Objekmodell einarbeiten muss.

Aspects

Aspects sehen auf dem ersten Blick wie Java-Klassen aus. Sie können Attribute und Methoden wie eine übliche Java-Klasse definieren. Zusätzlich können aspects noch Pointcuts und Advices defnieren.

public aspect LoggingAspect
{
public pointcut logPoints() :

execution( void Dose.oeffnen() );

before() : logPoints()
{
System.out.println(„Dose wird geöffnet“);
}
}
Beispiel 4 LoggingAspect für die Dose

Im Gegensatz zu Klassen können Aspects nicht instanziiert werden. Aspects bilden die Entitäten, in denen die Integrationsregeln schließlich festgehalten werden.

Weitere Möglichkeiten im Überblick

Mit Pointcuts und Advices sind die Sprachelemente für dynamisches Crosscutting definiert worden. AspectJ bietet zusätzlich noch die Möglichkeit, die statische Struktur einer Klasse zu beeinflussen. So kann man Klassen, neue Attribute und Methoden vergeben. Das ist besonders dann wichtig, wenn die neuen Aspekte eigene Zustände in den Instanzen verwalten müssen.

Im Beispiel 5 wird ein Attribut und eine Methode der Klasse Dose hinzugefügt. In dem Advice wird schließlich auf die eingefügte Methode zugegriffen. In der Pointcut Definition werden auch die Parameter definiert, die später dem Advice zur Verfügung gestellt werden sollen. Eingefangen wird die Doseninstanz in dem Pointcut durch das Sprachelement „this( )“.

public aspect LoggingAspect {
private Date Dose.oeffnungsDatum = null;
public Date Dose.getOeffnungsDatum() {
if (oeffnungsDatum == null)
oeffnungsDatum = new Date();
return oeffnungsDatum;
}

public pointcut logPoints(Dose dose) :
execution( void Dose.oeffnen() )
&&
this(dose);

before(Dose dose) : logPoints()
{
System.out.println(„Oeffnungsdatum: “+dose.getOeffnungsDatum();
}
}

Beispiel 5 LoggingAspect für die Dose

AspectJ bietet auch die Möglichkeit, Compiler-Fehler und -Warnungen zu definieren. Diese Fehler und Warnungen werden auch an Pointcuts gebunden. So kann man wie im Beispiel 6 gezeigt wird, eine Warnung defnieren, dass der Entwickler nicht in die Konsole schreiben soll, sondern die Logging-API verwenden soll.

declare warning : get(* System.out) : „Bitte die Logging API verwenden“
Beispiel 6 Compilerwarnungen definieren

Über diesen Mechanismus kann die Einhaltung einiger Programmierstandards innerhalb eines Projektes erzwungen werden.

Leave a Reply

Your email address will not be published. Required fields are marked *