2009-03-11 3 views
11

Ist es möglich, ein EJB "selbst zu injizieren", um lokale Methoden als Bean-Methoden aufzurufen? Es gibt Fälle, in denen dies vorteilhaft sein könnte, beispielsweise wenn Container-verwaltete Transaktionen verwendet werden und etwas in einer neuen Transaktion ausgeführt werden soll.Kann eine EJB3-Bean "selbst injizieren" und ihre eigenen Methoden über EJB-Container aufrufen?

Ein Beispiel, wie dies funktionieren könnte:

Foo.java:

@Local 
public interface FoO { 
    public void doSomething(); 
    public void processWithNewTransaction(); // this should actually be private 
} 

FooBean.java:

@Stateless 
public class FooBean implements Foo { 

    @EJB 
    private Foo foo; 

    public void doSomething() { 
     ... 
     foo.processWithNewTransaction(); 
     ... 
    } 

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 
    public void processWithNewTransaction() { 
     ... 
    } 
} 

Wenn ich processWithNewTransaction() zu einem anderen Bohne extrahieren, wäre es müssen als öffentliche Methode in der Schnittstelle ausgesetzt, obwohl es nur von FooBean aufgerufen werden sollte. (Das gleiche Problem tritt bei meinem obigen Code auf, deshalb gibt es einen Kommentar in der Schnittstellendefinition.)

Eine Lösung wäre, zu Bean-verwalteten Transaktionen zu wechseln. Dies würde jedoch erfordern, die gesamte Bean zu ändern, um ihre eigenen Transaktionen zu verwalten, und würde allen Methoden eine große Kesselplatte hinzufügen.

+0

Als Ergänzung zu den Antworten unten: Wenn Sie nicht die Methode mit neuer Transaktion in Ihrer lokalen Schnittstelle haben wollen, können Sie Ihren Bean Implementierung sowohl mit '@Local (Foo.class) mit Anmerkungen versehen' und ' @ LocalBean' und habe die Methode als öffentliche Methode nur in der Implementierungsklasse. – Gandalf

+0

OP - Bitte aktualisieren Sie dies, um die ausgewählte Antwort zu entfernen, die falsch ist. – NBW

Antwort

2

Update: Wie von anderen Antworten erwähnt, ist dies in der Tat technisch möglich. Bitte lesen Sie die Antworten von Csaba und Michael darüber, wie und warum es trotz der endlosen Rekursion funktioniert.


kann ich nicht 100% genaue Antwort geben, aber ich bin mir ziemlich sicher, dass dies nicht möglich ist.

Ich denke schon, weil der Container für die Injektion der Foo-Bohne in die Foo-Bohne zunächst eine Foo-Instanz erstellen müsste, die er anschließend injizieren kann. Aber um dies zu schaffen, muss er eine bereits existierende Instanz von Foo in das zu schaffende Foo einfügen ... was zu einer unendlichen Rekursion führt.

Wenn Sie separate Transaktionen benötigen, würde ich vorschlagen, die Dinge einfach zu halten und zwei unabhängige Beans/Schnittstellen zu erstellen.

+1

Zustimmen! Die rekursive Definition von Session-Beans ist keine gute Idee. – Timo

+0

Obwohl es vorgeschlagen wird, die Dinge getrennt zu halten, ist es in der Tat möglich (siehe Michael Nesterenko Antwort) – Lutz

+0

Dies ist mit ejb 2.1 und 3+ möglich. Entweder können Sie '@EJB Foo self' verwenden; oder Sie können @michael Nesterenkos Suggestion verwenden –

1

Interessante Frage. Ich erstelle niemals eine Methode mit einem anderen Transaktionsattribut in derselben Bean, das heißt, es wird nach Refactoring gefragt. Dies macht es normalerweise schwierig, Fehler in der Anwendung zu erkennen, wenn sie sich entwickeln.

EDIT: feste Tippfehler

+0

Es spielt keine Rolle, ob Sie ein anderes TX-Attribut benötigen oder nicht. Wenn Sie Ihre Logik nur so faktorisieren wollen, dass es für eine Methode sinnvoll ist, eine andere aufzurufen, werden Sie darauf stoßen, wenn Sie beispielsweise Entitäten übergeben (die in einem verwalteten Zustand bleiben müssen) oder mit der gleichen TX wie existieren möchten der Anrufer oder Sie möchten, dass Interzeptoren angerufen werden. Wenn Sie den Proxy nicht verwenden, wird keines dieser Dinge passieren. – NBW

+0

@NBW: Ich frage nicht, ob es passieren wird oder nicht. Ich sage nur, dass es Ihren Code schwerer lesbar macht und die Wahrscheinlichkeit erhöht, dass die Methode falsch aufgerufen wird, da Sie dies jetzt auf mehrere Arten tun können. Eine separate Komponente erleichtert die Wartung. Ihre Laufleistung kann jedoch variieren. – Antonio

1

würde ich eher ablehnen, ist es oft nützlich für die Transaktionsverwaltung eine lokale Bean-Methode über den Behälter zu rufen.

Genau wie im Beispiel, wenn Sie innerhalb einer Schleife eine lokale Bean-Methode aufrufen müssten, wäre es besser, eine Transaktion pro Iteration durchzuführen als für alle Iterationen. (vorausgesetzt, die Geschäftslogik war nicht "alles oder nichts" wie das Versenden einer Lieferung oder die Ausgabe von Lagerbeständen)

+0

Es hängt von Ihren Geschäftsanforderungen ab – deFreitas

8

Die Selbstinjektion eines EJB ist tatsächlich möglich. Der Grund, warum in diesem Fall keine unendliche Rekursion stattfindet, ist ziemlich einfach: Der Container injiziert keine tatsächliche Bean-Instanz aus dem Pool. Stattdessen injiziert es ein Proxy-Objekt. Wenn Sie eine Methode für den injizierten Proxy (foo) aufrufen, ruft der Container eine Bean-Instanz aus seinem Pool ab oder erstellt eine Bean-Instanz, wenn keine Instanzen verfügbar sind.

8

Es ist möglich, eine self injection zu tun. Sie müssen SessionContext verwenden.

SessionContext sc = ... 
sc.getBusinessObject(FooBean.class).processWithNewTransaction() 
+1

Ja und eine andere Möglichkeit ist über einen @ EJB Verweis auf eine Bean des eigenen Typs hier Foo. (Siehe [So wird Self-Invoke EJB 3.x mit (out) "this"] (http://www.adam-bien.com/roller/abien/entry/how_to_self_invoke_ejb)) – Lutz

Verwandte Themen