2017-03-21 4 views
0

Angenommen, wir haben folgende KlasseGleiche Klasse aufrufen nicht wirksam in Spring AOP cglib

@Service 
class MyClass { 

    public void testA() { 
     testB(); 
    } 

    @Transactional 
    public void testB() { ... } 
} 

Wenn wir nun myClass.testA(); in Test aufrufen, dann @Transactional auf testB wird nicht wirksam. Der Grund, denke ich, folgt.

CGLIB eine Proxy-Bean für MyClass, wie diese erstellen:

Class Cglib$MyClass extends MyClass { 

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

Nun rufen wir myClass.testA(), die MyClass.testB() statt Cglib$MyClass.testB() aufrufen wird. So ist @Transactional nicht effektiv. (Habe ich Recht?)

Ich habe versucht, @Transactional für beide Methoden hinzufügen (d. H. testA() und testB()). Die Proxy-Klasse sollte das mögen.

Class Cglib$MyClass extends MyClass { 

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

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

In diesem Fall ist, obwohl wir MyClass.testB() erfolgreich Cglib$MyClass.testA() aufrufen, wird geht es nach wie vor.

Also meine Schlussfolgerung ist, zwei Methoden in der gleichen Klasse gegenseitig aufrufen wird machen aop Annotation nicht wirksam werden, es sei denn, wir verwenden AopContext.currentProxy().

Bin ich direkt auf oben raten? Vielen Dank für Ihren Rat!

Antwort

0

Sie haben es fast richtig. Der Proxy sieht eher wie folgt aus:

class Cglib$MyClass extends MyClass { 

    MyClass delegate; 

    @Override 
    public void testB() { 
    // ...do transactional things 
    delegate.testB(); 
    } 
} 

Jeder Anruf wird von Spring weitergeleitet, weshalb Ihre verschachtelten Annotationen nicht aktiviert sind.

Auch wenn eine virtuelle Methode wie testA außer Kraft gesetzt wurde, konnte Spring nicht vermeiden, die überschriebene Methode aufzurufen.

0

Es ist eine bekannte und documented Tatsache, dass Frühling AOP aufgrund seiner Proxy-basierten Natur (bitte für den Begriff „Selbst Aufruf“ suchen), nicht und nicht die interne Methode aufruft wie this.someMethod(..) erfassen kann.

Also wie Sie gesagt haben, müssen Sie entweder explizit auf das exposed Proxy-Objekt verweisen oder alternativ von Spring AOP auf volle AspectJ via load-time weaving wechseln.