同一个类调用在 Spring AOP cglib 中无效

zch*_*hen 5 java aop cglib

假设我们有以下课程

@Service
class MyClass {

    public void testA() { 
        testB();
     }

    @Transactional
    public void testB() { ... }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我们myClass.testA();在 test 中调用,那么@TransactionalontestB将不会生效。我认为的原因如下。

Cglib 将创建一个代理 bean MyClass,如下所示:

Class Cglib$MyClass extends MyClass {

    @Override
    public void testB() {
        // ...do transactional things
        super.testB();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们调用myClass.testA(),它将调用MyClass.testB()而不是Cglib$MyClass.testB()。所以@Transactional是无效的。(我对吗?)

我尝试@Transactional为这两种方法(即testA()testB())添加。代理类应该是这样的。

Class Cglib$MyClass extends MyClass {

    @Override
    public void testA() {
        // ...do transactional things
        super.testA();
    }

    @Override
    public void testB() {
        // ...do transactional things
        super.testB();
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,虽然我们成功调用了Cglib$MyClass.testA(),但它仍然会转到MyClass.testB()

所以我的结论是,同一个类中的两个方法相互调用会导致aop注解失效,除非我们使用AopContext.currentProxy().

我上面的猜测是对的吗?非常感谢您的建议!

kri*_*aex 5

这是一个众所周知的记录(请搜索术语“自我调用”)事实Spring AOP中,由于其基于代理的性质,不会,也无法捕捉的内部方法调用一样this.someMethod(..)

因此,正如您所说,您要么需要显式引用公开的代理对象,要么通过加载时编织从 Spring AOP 切换到完整的AspectJ


Raf*_*ter 4

你几乎是对的。代理看起来更像这样:

class Cglib$MyClass extends MyClass {

  MyClass delegate;

  @Override
  public void testB() {
    // ...do transactional things
    delegate.testB();
  }
}
Run Code Online (Sandbox Code Playgroud)

任何调用都会由 Spring 转发,这就是您的嵌套注释未激活的原因。

另外,如果像这样的虚方法testA被重写,Spring 就无法避免调用被重写的方法。