Wie mit AOP (AspectJ) auf statiche Felder für den advice zugreifen?

takidoso

Erfahrenes Mitglied
Hallo und Halli,
ich habe mal angefangen mich ein wenig mit ApectJ auseinanderzusetzen.
Irgendwie habe ich noch nicht herausgefunden wie man auf statische Elemente zugreift, um sie in einem advice zu verwenden.
Mein anwendungsgeiebt wäre log4j, der einfach für bestimmte Klassen verwendet werden soll um start und beginn einer Routine zu loggen.
Die Beispiele die ich finde sind ausnahms los mit schnöden System.outs bestückt.
ich habe aber dann noch etwas gefunden, was ich als eine Art Workaround ansehe und was zwar funktioniert aber ein wenig unelegant mi rerscheint, da man dafür in der Laufzeit die AspectJ Bibliothek benötigt. Dieser Workaround sieht wie folgt aus:
Java:
import org.apache.log4j.Logger;
import org.aspectj.lang.Signature;

import de.lala.Klasse1
import de.lala.Klasse2;
import de.lala.Klasse3;

public aspect Performance
{
	
	pointcut classes()      : within(Klasse1) || within (Klasse2) || within(Klasse3);
	pointcut constructors() : classes() && execution(new(..));
	pointcut methods()      : classes() && execution (* *(..));
	
	
	before () : constructors() || methods()
	{
		Signature sig    = thisJoinPointStaticPart.getSignature();
		Logger    logger = Logger.getLogger(sig.getDeclaringType());
		logger.info("----- start:"+sig);
	}
	
	after () : constructors() || methods()
	{
		Signature sig    = thisJoinPointStaticPart.getSignature();
		Logger    logger = Logger.getLogger(sig.getDeclaringType());
		logger.info("----- end:"+sig);
	}
}

So frage ich mich ob man nicht auch ohne die Reflektion auskommt und man stattdessen das typische Feld "logger" welche sin allen Klassen statisch vorliegt verwendet werden kann? Mir ist es da leider nicht gelungen bekam dann immer Compilerfehler.

Hat da jemand eine Idee oder ein Rezept, oder geht das so gar nicht, weil in AspectJ nicht vorgesehen?

Mit bestem Dank für Hinweise im Voraus

Takidoso
 

Thomas Darimont

Erfahrenes Mitglied
Hallo,

das kann man beispielsweise mit einem privileged Aspect und entsprechender target(...) Pointcuts machen.
Hier mal ein kleines Beispiel dazu:

Das Beispiel (AOPExample):
Java:
package de.tutorials;

import de.tutorials.service.Service;
import de.tutorials.service.Service1;
import de.tutorials.service.Service2;

public class AOPExample {
	public static void main(String[] args) {
		Service service1 = new Service1();
		Service service2 = new Service2();

		service1.op();
		service2.op();
	}
}

Service-Interface:
Java:
package de.tutorials.service;

public interface Service {
	void op();
}

AbstractService:
Java:
package de.tutorials.service;

import java.lang.invoke.MethodHandles;
import java.util.logging.Logger;

public abstract class AbstractService implements Service {
	protected static Logger logger = Logger.getLogger(MethodHandles.lookup().lookupClass().getName());
}

Service1:
Java:
package de.tutorials.service;

public class Service1 extends AbstractService {
	public void op() {
		logger.info(getClass() + " -> op()");
	}
}

Service2:
Java:
package de.tutorials.service;

public class Service2 extends AbstractService {
	public void op() {
		logger.info(getClass() + " -> op()");
	}
}

Hier unser TracingAspect:
Java:
package de.tutorials.aspect;

import de.tutorials.service.AbstractService;

public privileged aspect TracingAspect { //privileged required to access protected static logger in AbstractService
	pointcut inService() : within(de.tutorials.service.AbstractService+) && !within(de.tutorials.service.AbstractService);

	pointcut serviceConstructors() : inService() && execution(new(..));

	pointcut serviceMethods(): inService() && execution (* *(..));

	before(AbstractService service) : (serviceConstructors() || serviceMethods()) && target(service){
		AbstractService.logger.info("----- start:"
				+ thisJoinPointStaticPart.getSignature());
	}

	after(AbstractService service) : (serviceConstructors() || serviceMethods()) && target(service){
		AbstractService.logger.info("----- end  :"
				+ thisJoinPointStaticPart.getSignature());
	}
}

Ausgabe:
Code:
Feb 14, 2013 2:12:06 AM de.tutorials.aspect.TracingAspect ajc$before$de_tutorials_aspect_TracingAspect$1$62506b3a
INFO: ----- start:de.tutorials.service.Service1()
Feb 14, 2013 2:12:06 AM de.tutorials.aspect.TracingAspect ajc$after$de_tutorials_aspect_TracingAspect$2$62506b3a
INFO: ----- end  :de.tutorials.service.Service1()
Feb 14, 2013 2:12:06 AM de.tutorials.aspect.TracingAspect ajc$before$de_tutorials_aspect_TracingAspect$1$62506b3a
INFO: ----- start:de.tutorials.service.Service2()
Feb 14, 2013 2:12:06 AM de.tutorials.aspect.TracingAspect ajc$after$de_tutorials_aspect_TracingAspect$2$62506b3a
INFO: ----- end  :de.tutorials.service.Service2()
Feb 14, 2013 2:12:06 AM de.tutorials.aspect.TracingAspect ajc$before$de_tutorials_aspect_TracingAspect$1$62506b3a
INFO: ----- start:void de.tutorials.service.Service1.op()
Feb 14, 2013 2:12:06 AM de.tutorials.service.Service1 op
INFO: class de.tutorials.service.Service1 -> op()
Feb 14, 2013 2:12:06 AM de.tutorials.aspect.TracingAspect ajc$after$de_tutorials_aspect_TracingAspect$2$62506b3a
INFO: ----- end  :void de.tutorials.service.Service1.op()
Feb 14, 2013 2:12:06 AM de.tutorials.aspect.TracingAspect ajc$before$de_tutorials_aspect_TracingAspect$1$62506b3a
INFO: ----- start:void de.tutorials.service.Service2.op()
Feb 14, 2013 2:12:06 AM de.tutorials.service.Service2 op
INFO: class de.tutorials.service.Service2 -> op()
Feb 14, 2013 2:12:06 AM de.tutorials.aspect.TracingAspect ajc$after$de_tutorials_aspect_TracingAspect$2$62506b3a
INFO: ----- end  :void de.tutorials.service.Service2.op()

Ansonsten schau mal hier:
http://www.tutorials.de/java/300525-aspectj-und-eclipse.html
http://www.tutorials.de/java/349813-beispiel-fuer-einfache-logging-configuration-mit-aspectj.html
http://www.tutorials.de/java/254041-ablaufverfolgung-eines-java-programmes.html

Gruß Tom