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?
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. –
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? –
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) –