Spring AOP对于具有接口的类无能为力

Yev*_*i N 4 java inheritance aop spring spring-aop

我知道Spring AOP的功能非常有限(它只能切入Spring bean的类的公共方法,并且只有在从类外部调用这些方法时).但是现在我发现了涉及接口的另一个令人困惑的限制.

通常,如果一个类被子类化,Spring AOP可以切入所有方法(甚至是被覆盖的方法):

public class A {
    public void methodA() { } //OK, can cut in
}

public class B extends A {
    @Override
    public void methodA() { } //OK, can cut in

    public void methodB() { } //OK, can cut in
}
Run Code Online (Sandbox Code Playgroud)

但是当我们在混合中添加一个接口时,对于Spring AOP来说,事情变得非常糟糕:

public interface I {
    public void methodA();
}

public class A implements I {
    @Override
    public void methodA() { } //OK, can cut in

    public void methodB() { } //Fail, cannot see or cut into this method
}

public class B extends A {
    @Override
    public void methodA() { } //Fail, cannot see or cut into this method

    public void methodC() { } //Fail, cannot see or cut into this method
}
Run Code Online (Sandbox Code Playgroud)

首先,Spring AOP只能切入界面中的方法,其他任何东西 - 它都看不到.其次,它只能切入直接实现接口方法的方法 - A.methodA().它无法切入由B覆盖的相同方法.

我使用通用切入点表达式"execution(* method*(..))"来切入所有可能的方法,因此它不是表达式问题.

这种限制有什么办法吗?或者我应该忘记Spring AOP并使用不同的方法?

更新: 好的,我找到了问题的真正原因.我实际上是依靠Intellij IDEA的AOP插件来测试它.它应该将切入点链接到所有受影响的方法.但它使用的是"旧的"动态JDK代理策略,而不是新的CGLIB策略.所以它没有将它链接到所有方法,但是当我实际运行我的程序时,它会正确地切入所有方法.

我正在使用Spring Boot 2,它使用'新'CGLIB策略.但是在SB1上它可能仍然使用"旧的"动态JDK代理策略,因此它可能仍然无法在那里工作.

fan*_*kai 5

Spring将使用动态代理或cglib来实现AOP.

如果没有接口,则选择Cglib,然后它将有效地创建目标类的子类,并覆盖目标类中的所有方法.通过这种方式,除最终和静态方法外,所有方法都可以切入.

如果目标类是带接口的,那么Spring可能会使用其中一个接口使用动态代理,显然这只会影响接口中声明的方法.

在spring-boot 2.0之前,动态代理是默认策略.现在Cglib是spring-boot 2.0之后的默认策略.

在我看来,Spring可能会采用动态代理方法.您可以在application.yaml中添加spring.aop.proxy-target-class:true以强制使用Cglib.

如果您仍有问题,最好发布更完整的代码段,显示如何调用mothods.