Spring(Java):在非线性类层次结构中不触发Aspect

Ser*_*fel 5 java aop spring class-hierarchy aspect

当类层次结构不是线性时,在基接口上定义时不会触发方面.

最有趣的是:当将实现的委托实现(参见最后一个代码块)添加到实现的父类时,测试变为绿色(Aspect按预期触发).

问题:为什么它不能像示例中所描述的那样工作,为什么它与委托实现一起工作?

示例(抱歉,没有找到更短的示例):

测试:

 @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);
}
Run Code Online (Sandbox Code Playgroud)

方面:

@Aspect
@Component
public static class MyAspect {

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

接口:

public static interface TheInterface {
    void doSomething();
}

public static interface SpecializedInterface extends TheInterface {
    // inherits doSomething
    // defines some other methods
}
Run Code Online (Sandbox Code Playgroud)

抽象实现(模板模式):

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
}
Run Code Online (Sandbox Code Playgroud)

实现bean:

@Component
public static class TemplateImplementation extends SpecializedTemplate {
    @Override
    void doOneStep() {
        implementationCalled = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

(如果你有兴趣:测试设置:)

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

丑陋的解决方法:将此代码段添加到SpecializedTemplate

    @Override
    public void doSomething() {
        super.doSomething();
    }
Run Code Online (Sandbox Code Playgroud)

那么,为什么这种解决方法必要?

kri*_*aex 0

Thomas Stets已经解释了字节码和 JVM 的内容,所以我只会为您的问题提供一个解决方案,另请参阅我对一个非常相似的问题的回答

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

即,您的切入点针对实际定义方法的基本接口,然后将目标限制为您选择的专用子接口。这应该会让你的测试变绿。