Spring AOP Parameter übergabe an Advice

KrisKul

Grünschnabel
Hallo zusammen

Folgendes Szenario:

Klasse1 implementiert Interface1. Und hat die Variablen a und b und die dazugehörigen Getter und Setter definiert das Interface 1.

Klasse2 implementiert Interface2, welches nur eine Methode definiert.

Nun soll über AOP definiert werden, dass vor dem Aufruf der getA() Methode des Interface1 die Methode der Klasse 2 aufgerufen werden soll.

Dies sollte so gelösst sein.
Code:
execution(* Interface1.getA(..))

Die schwierigkeit für mich ist, dass die Methode des Interface2 bzw. der Advice die Variable B der Klasse1 benötigt. Wie kann ich diese übergeben?

Ich habe es damit versucht, klappt aber auch nicht.

Code:
<aop:pointcut 
			    expression="execution(* Klasse1.getA(..)) and this(b)"
			    id="geta"/>
		    <aop:before pointcut-ref="geta" method="receiveData" arg-names="b"/>

Code:
<aop:pointcut 
			    expression="execution(* Klasse1.getA(..)) and args(b)"
			    id="geta"/>
		    <aop:before pointcut-ref="geta" method="receiveData" arg-names="b"/>
 
Zuletzt bearbeitet:

Thomas Darimont

Erfahrenes Mitglied
H/allo,

irgendwie komme ich mit deiner Erklärung nicht ganz klar - hat deine getA Methode an interface1 Parameter oder nicht? Wenn das ein normaler Java Bean Style - Getter ist, dann wohl nicht ;-)

Hier mal ein kleines Beispiel mit Spring AOP mit AspectJ Style Pointcut Definitions:

Interface1
Java:
package de.tutorials.aop.example42;

public interface Interface1 {

	String getB();

	String getA();

	String lookup(String key);
}

Interface2:
Java:
package de.tutorials.aop.example42;

public interface Interface2 {
	void receiveData(Object arg);
}

Class1:
Java:
package de.tutorials.aop.example42;

public class Class1 implements Interface1 {
	String a;
	String b;

	@Override
	public String getA() {
		return a;
	}

	public void setA(String a) {
		this.a = a;
	}

	@Override
	public String getB() {
		return b;
	}

	public void setB(String b) {
		this.b = b;
	}
	
	@Override
	public String lookup(String key) {
		return "Result_for_"+key;
	}

}

Class2:
Java:
package de.tutorials.aop.example42;

public class Class2 implements Interface2{

	@Override
	public void receiveData(Object arg) {
		System.out.println("Received Data: " + arg);
	}

}

Spring Konfiguration context.xml
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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="some1" class="de.tutorials.aop.example42.Class1"/>
	
	<bean id="some2" class="de.tutorials.aop.example42.Class2"/>
	
	<aop:config>
		<aop:aspect ref="some2">
		<aop:before  method="receiveData"  pointcut="execution(* *..Interface1+.lookup(..)) and args(arg)"/>
		</aop:aspect>
	</aop:config>

</beans>

Main Klasse:
Java:
package de.tutorials.aop.example42;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
	public static void main(String[] args) {
		Interface1 o = new ClassPathXmlApplicationContext("example42/context.xml").getBean(Interface1.class);
		System.out.println(o.lookup("abc"));
	}

}

Ausgabe:
Code:
2012-06-28 18:32:26,102 0    [main] INFO  org.springframework.context.support.ClassPathXmlApplicationContext  - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@144f1ada: startup date [Thu Jun 28 18:32:26 CEST 2012]; root of context hierarchy
2012-06-28 18:32:26,145 43   [main] INFO  org.springframework.beans.factory.xml.XmlBeanDefinitionReader  - Loading XML bean definitions from class path resource [example42/context.xml]
2012-06-28 18:32:26,328 226  [main] INFO  org.springframework.beans.factory.support.DefaultListableBeanFactory  - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@cae945: defining beans [some1,some2,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0]; root of factory hierarchy
Received Data: abc
Result_for_abc

Wenn du deinen Advice noch etwas generischer machen möchtest könntest du diesen auch so Implementieren:

Interface1:
Java:
package de.tutorials.aop.example42;

import org.aspectj.lang.JoinPoint;

public interface Interface2 {
	void receiveData(JoinPoint jp);
}

Class2:
Java:
package de.tutorials.aop.example42;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;

public class Class2 implements Interface2 {

	@Override
	public void receiveData(JoinPoint jp) {
		System.out.println("Received Data: " + Arrays.toString(jp.getArgs())
				+ " " + jp.getStaticPart().getSignature());

	}

}

Konfiguration:
XML:
...
	<aop:config>
		<aop:aspect ref="some2">
		<aop:before  method="receiveData"  pointcut="execution(* *..Interface1+.lookup(..))"/>
		</aop:aspect>
	</aop:config> 
...

Ausgabe:
Code:
2012-06-28 18:42:47,678 0    [main] INFO  org.springframework.context.support.ClassPathXmlApplicationContext  - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@556be8a0: startup date [Thu Jun 28 18:42:47 CEST 2012]; root of context hierarchy
2012-06-28 18:42:47,724 46   [main] INFO  org.springframework.beans.factory.xml.XmlBeanDefinitionReader  - Loading XML bean definitions from class path resource [example42/context.xml]
2012-06-28 18:42:47,909 231  [main] INFO  org.springframework.beans.factory.support.DefaultListableBeanFactory  - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@cae945: defining beans [some1,some2,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0]; root of factory hierarchy
Received Data: [abc] String de.tutorials.aop.example42.Interface1.lookup(String)
Result_for_abc

Gruß Tom
 
Zuletzt bearbeitet von einem Moderator:

KrisKul

Grünschnabel
Hi Tom

Danke für die Antwort und die Mühe.
Ich versuche es mal genauer zu beschreiben.

Interface1
Code:
package de.tutorials.aop.example42;
 
public interface Interface1 {
    String getB();
    int getA();
    String lookup();
}

Interface 2
Code:
package de.tutorials.aop.example42;
 
public interface Interface2 {
    void receiveData(int arg);
}


Class1
Code:
package de.tutorials.aop.example42;
 
public class Class1 implements Interface1 {
    int a;
    String b;
 
    @Override
    public int getA() {
        return a;
    }
    public void setA(int a) {
        this.a = a;
    }
    @Override
    public String getB() {
        return b;
    }
    public void setB(String b) {
        this.b = b;
    }
    @Override
    public String lookup() {
        return "Lookup";
    }
}


Class2:
Code:
package de.tutorials.aop.example42;
 
public class Class2 implements Interface2{
    @Override
    public void receiveData(int arg) {
        System.out.println("Received Data: " + arg);
    }
}

Wenn die lookup()-Methode aufgerufen wird, dann soll im Grunde folgendes geschehen.
Schema:
Code:
class2.recieve(class1.getA());
String s = class1.lookup();

Nun soll vor dem Ausführen von lookup() die recieve() Methode ausgeführt werden. Als Parameter für die recieve()-Methode soll a aus Class1 übergeben werden.

Ich habe es mit einem Around Advice versucht, konnte jedoch das gewünschte Ziel nicht erreichen, da die joinPoint.proceed()-Methode den Rückgabewert der Methode liefert.
 

KrisKul

Grünschnabel
Hey Tom.

Danke. Hat sich im Grunde erledigt. Habe es nochmal ausprobiert. Die Lösung ist der JoinPoint Parameter im Before-Advice. Dort kann ich das Target-Objekt abfragen.

Vielen Dank.