2015-02-04 4 views
5

Wenn die Klassenhierarchie nicht linear ist, wird Aspekt nicht ausgelöst, wenn sie auf der Basisschnittstelle definiert ist.Spring (Java): Aspekt wird nicht in nichtlinearer Klassenhierarchie ausgelöst

Am interessantesten: Wenn Sie delegierende Implementierung (siehe letzten Codeblock) zur übergeordneten Klasse der Implementierung hinzufügen, wird der Test grün (Aspekt wird wie erwartet ausgelöst).

Frage: Warum funktioniert es nicht wie im Beispiel beschrieben und warum funktioniert es mit der delegierenden Implementierung?

Beispiel (sorry, nicht kürzer Beispiel gefunden):

Test:

@Autowired 
private TheInterface underTest; 
private static boolean aspectCalled; 
private static boolean implementationCalled; 

@Test 
public void aspectTest() throws Exception { 
    aspectCalled = false; 
    implementationCalled = false; 

    underTest.doSomething(); 

    assertTrue("Implementation not called!", implementationCalled); 
    assertTrue("Aspect not called!", aspectCalled); 
} 

Richtung:

@Aspect 
@Component 
public static class MyAspect { 

    @Before("execution(* *..SpecializedInterface+.doSomething())") 
    public void applyAspect() { 
     aspectCalled = true; 
    } 
} 

Schnittstellen:

Zusammenfassung i mplementations (Template-Muster):

public static abstract class BaseTemplate implements TheInterface { 
    abstract void doOneStep(); 

    @Override 
    public void doSomething() { 
     // do some stuff and 
     doOneStep(); 
    } 
} 

public static abstract class SpecializedTemplate extends BaseTemplate implements SpecializedInterface { 
    // some other methods 
} 

Implementierung Bohne:

@Component 
public static class TemplateImplementation extends SpecializedTemplate { 
    @Override 
    void doOneStep() { 
     implementationCalled = true; 
    } 
} 

(Wenn Sie interessiert sind: Testaufbau :)

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = MyConfig.class) 
public class AopTest { 
    @Configuration 
    @EnableAspectJAutoProxy 
    @ComponentScan(basePackageClasses = AopTest.class) 
    public static class MyConfig { 
    } 
    ... 

hässliche Lösung: Fügen Sie diese Schnipsel SpecializedTemplate

@Override 
    public void doSomething() { 
     super.doSomething(); 
    } 

Warum ist diese Problemumgehung erforderlich?

+1

Ich bin nicht zu fest in den Details, aber das ist meine Vermutung: @Before ("Ausführung (* * .. SpecializedInterface + .doSomething())") es den Aspekt auf doSomething() in jeder Klasse anwenden Implementierung von SpecializedInterface. SpecializedTemplate enthält doSomething() (bytecode-weise) nicht, so dass der Aspekt nicht angewendet wird. Sobald Sie Ihre Problemumgehung hinzugefügt haben, enthält die Klasse die Methode und der Aspekt kann angewendet werden. –

+0

Aber was ist mit der TemplateImplementation (Implementierung von Bean)? Enthält es die doSomething() - Methode in Bytecode? Kopiert der Java-Compiler alle Implementierungen in abstrakten Klassen in die konkreten Klassen, also hat er auch die Methode auf Bytecode-Ebene? –

+1

Nein, TemplateImplementation hat keinen Bytecode für die geerbten Methoden. Wenn Sie in TemplateImplementation doSomething() aufrufen, geht die Java-VM zur Laufzeit rückwärts durch die Klassenhierarchie, bis sie eine Implementierung findet. Wenn Sie Ihre Problemumgehung verwenden, wird die Implementierung in SpecializedTemplate gefunden, in der der Aspekt angewendet wurde (da der Punktcut angepasst wurde). Ohne Workaround muss es zurück zu BaseTemplete gehen, wo der Aspekt nicht angewendet wurde (da er nicht mit dem Pointcut übereinstimmt) –

Antwort

0

Thomas Stets hat bereits erklärt, den Bytecode und JVM stuff, so dass ich nur eine Lösung für Ihr Problem, siehe auch meine answer auf eine sehr ähnliche Frage.

@Aspect 
public static class MyAspect { 
    @Before("execution(* *..TheInterface+.doSomething()) && target(specializedInterface)") 
    public void applyAspect(SpecializedInterface specializedInterface) { 
     aspectCalled = true; 
    } 
} 

I.e. Ihr Pointcut richtet sich an die Basisschnittstelle, die die Methode definiert, und Sie beschränken das Ziel auf die spezialisierte Subschnittstelle Ihrer Wahl. Dies sollte Ihren Test grün machen.

Verwandte Themen