Einführung in die aspektorientierte Programmierung, Teil 3

Eine Welt der Wunder

Arno Schmidmeier

Die Programmierumgebung AspectJ [1] bietet Entwicklern eine Erweiterung der Java-Programmiersprache. Welcher Nutzen entsteht aber aus der Verwendung von AspectJ? Unsere Reihe bietet eine Einführung in die aspektorientierte Programmierung sowie einen dritten Praxisteil, in dem gezeigt wird, wie das Java Exception Handling konzipiert ist und wie es mit geringem Aufwand richtig eingesetzt werden kann.

Im ersten Teil unserer Serie [2] sahen wir, wie man mit Pointcuts und Advices einige typische Probleme der objektorientierten Programmierung elegant beheben kann. Im zweiten Teil [3] sahen wir, wie AspectJ einige Anomalien in herkömmlichen Klassenstrukturen behebt. In diesem Teil betrachten wir AOP in Action, wie mithilfe von AOP Exception Handling einfacher und konsequenter implementiert wird. Eines der zentralen Designziele der Programmiersprache Java war ein stabilerer und qualitativ besserer Code. Dieses Ziel unterstützt auch das Exception Handling. Leider benötigt guter Code einiges an Arbeit und damit auch an Zeit. Zeit, die man in heutigen Projektplänen immer seltener findet. Aus diesem Grund wird die Fehlerbehandlung nicht oder nur schlampig durchgeführt. In diesem Artikel beschränke ich mich auf die wichtigsten Aspekte einer guten Fehlerbehandlung. Dabei zeige ich, wie diese mit Aspekten implementiert werden können. Dabei wird deutlich, was im Bereich AspectJ modularisiert werden kann und was immer noch manuelle Arbeit erfordert, da der Algorithmus mit der Geschäftslogik gegebenenfalls angepasst werden muss.Betrachten wir Exceptions in der Programmiersprache Java. Exceptions sind eine Art außergewöhnlicher Rückgabewert, da normale Rückgabewerte nicht immer ausreichen. Das alte Konzept, einfach einen Fehlerwert zurückzugeben, leidet unter zwei Nachteilen:Erstens, wie kann man unterscheiden, ob eine Funktion entweder keine Daten liefern konnte, z.B. weil keine vorhanden sind, oder ob ein technischer Fehler aufgetreten ist. Wie will man z.B. unterscheiden, ob die Funktion Public Kunde findNextKonto() kein nächstes Konto findet, weil es nicht existiert, oder ob ein unvorhergesehener Fehler auftrat, der sie daran hinderte, das Ergebnis zu liefern?Zweitens, die Fehlermeldung, die Fehlerdiagnose und das Fehlerbehandlung unterblieben oft, da niemand den Entwickler zwang, minimalen Code zur Fehlerdiagnose einzubauen. Fehler bleiben bei diesem Ansatz meist lange unentdeckt und erzeugen oft interessante Folgefehler, die schwer zu lokalisieren sind.Java bietet dazu die Klasse Exception an. Alle Exceptions, die von dieser Klasse und nicht von Runtime Exception abgeleitet sind, müssen vom Entwickler abgefangen werden. Aus diesem Grund existiert folgende Regel (Regel Nummer eins):Jedes Auftreten einer Exception muss genau einmal behandelt werden.Einfaches Ignorieren wie z.B. mit folgendem Code:

public aspect HandleException {

public pointcut CatchRuntimeException(RuntimeException ex):handler(RuntimeException+)&&args(ex);

before(RuntimeException ex):CatchRuntimeException(ex){
logRuntimeException(ex,thisJoinPoint);
}

public pointcut CatchNonRuntimeException(Exception ex):handler(Exception+)&&args(ex)&&!args(RuntimeException+);

before(Exception ex):CatchNonRuntimeException(ex){
logException(ex,thisJoinPoint);
}


public void logRuntimeException(RuntimeException ex,JoinPoint JP){
String c=null;
c = getClassAtthisJoinPoint(JP);
//einen Aufruf auf das verwendete Loggin API.
}

/** Gibt die Klasse, bei der sich der Joinpoint befindet zurück.*/
private static String getClassAtthisJoinPoint(JoinPoint JP) {
String c;
Object obj=JP.getThis();
if (obj==null){
obj=JP.getTarget();
}
if (obj!=null)
c=obj.getClass().getName();
else c="unknown";
return c;
}

public void logException(Exception ex,JoinPoint JP){
String c=getClassAtthisJoinPoint(JP);
//einen Aufruf auf das verwendete Loggin API.
}

static void LogThisJoinPoint(JoinPoint JP){
StringBuffer sb=new StringBuffer(JP.toString());
sb.append(" ");
Object obj[]=JP.getArgs();
for(int i=0;i

Gerade der Code für die Fehlerbehandlung ist oft redundant. Viele von diesen Redundanzen lassen sich einfach mit Aspekten eliminieren. Jedoch können Aspekte auch keine Wunder vollbringen und den Algorithmus um manuell zu definierende Verzweigungen im Fehlerfall erweitern.Bestimmte Fehler-Policies können einfach und zentral an einer Stelle definiert werden. Der Compile- und Webvorgang des AspectJ Compiler stellt damit sicher, dass sie richtig eingesetzt werden. Fehlerträchtige manuelle Codestyle Guides werden dadurch überflüssig. Fehler-Auditing ist dafür ein Beispiel. Auch Fehlerbehebungsverfahren können wir modularisieren. Da wir diese meist nur an ausgewählten Stellen an den Code binden wollen, verwenden wir hier am besten abstrakte Aspekte für die Aspektdefinition und konkrete Aspekte für die Definition, wo sie hingewebt werden müssen. Oft hat man aus technischen oder organisatorischen Gründen nicht die Möglichkeit, eine aspektorientierte Sprache einzusetzen. In diesem Fall kann man auf aspektorientierte Frameworks ausweichen.Mit mehreren Jahren Erfahrung in der AOP-Entwicklung ist Arno Schmidmeier ein erfahrener AOP Consultants. Seine weiteren Schwerpunkte sind Softwaredesign, IT-Architekturen und Middleware. Er ist unter arno@aspectsoft.de zu erreichen.Links und Literatur[1] www.eclipse.org/aspectj/[2] Arno Schmidmeier: Aspekte von Java, in Java Magazin 12.2003[3] Arno Schmidmeier: Korrektes Exception Handling mit AspectJ, in Java Magazin 2.2004[4] www.refactoring.com

Geschrieben von
Arno Schmidmeier
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.