2009-03-11 6 views
11

Est-il possible de "s'injecter soi-même" un EJB pour appeler des méthodes locales comme méthodes de haricot? Dans certains cas, cela pourrait être favorable, par exemple si des transactions gérées par des conteneurs sont utilisées et que quelque chose devrait être accompli dans une nouvelle transaction.Un bean EJB3 peut-il s'auto-injecter et appeler ses propres méthodes via un conteneur EJB?

Un exemple comment cela pourrait fonctionner:

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() { 
     ... 
    } 
} 

Si j'extrais processWithNewTransaction() à un autre grain, il aurait besoin d'être exposée comme une méthode publique dans l'interface, même si elle doit être appelée uniquement par FooBean. (Le même problème concerne mon code ci-dessus, c'est pourquoi il y a un commentaire dans la définition de l'interface.)

Une solution consisterait à basculer vers des transactions gérées par le bean. Cependant, cela nécessiterait de changer le bean entier pour gérer ses propres transactions, et ajouterait beaucoup de plaque de chaudière à toutes les méthodes.

+0

En complément des réponses ci-dessous: Si vous ne voulez pas avoir la méthode avec une nouvelle transaction dans votre interface locale, vous pouvez annoter votre implémentation de haricots à la fois '@Local (Foo.class)' et ' @ LocalBean' et ont la méthode comme méthode publique dans la classe d'implémentation seulement. – Gandalf

+0

OP - Veuillez le mettre à jour pour décocher la réponse sélectionnée qui est incorrecte. – NBW

Répondre

2

Mise à jour: Comme cela est indiqué par d'autres réponses, cela est techniquement possible. S'il vous plaît voir les réponses de Csaba et Michael sur comment et pourquoi cela fonctionne malgré la récurrence sans fin apparente.


Je ne peux pas donner une réponse précise à 100% mais je suis à peu près sûr que ce n'est pas possible. Je pense que parce que pour injecter le bean Foo dans le haricot Foo lui-même, le conteneur devrait initialement créer une instance de Foo qu'il pourra ensuite injecter. Mais pour créer ceci il doit injecter une instance déjà existante de Foo dans le Foo à créer ... ce qui conduit à une récursion infinie.

Si vous avez besoin de transactions séparées, je vous suggère de garder les choses simples et de créer deux beans/interfaces indépendants.

+1

D'accord! La définition récursive des beans session n'est pas une bonne idée. – Timo

+0

Bien qu'il soit suggéré de garder les choses séparées, il est en effet possible (voir michael nesterenko réponse) – Lutz

+0

Ceci est possible avec ejb 2.1 et 3+. Soit vous pouvez utiliser '@EJB Foo self'; ou vous pouvez utiliser la suggestion de @michael nesterenko –

1

Question intéressante. Je ne crée jamais une méthode avec un attribut de transaction différent dans le même bean, c'est-à-dire que cela nécessite un refactoring. Cela rend généralement difficile la détection de bogues dans l'application lorsqu'elle évolue.

EDIT: fautes de frappe fixe

+0

Peu importe que vous ayez ou non besoin d'un attribut TX différent. Si vous voulez simplement factoriser votre logique de telle sorte qu'il soit logique qu'une méthode en appelle une autre, vous rencontrerez ceci si par exemple vous passez des entités (qui doivent rester dans un état géré) ou souhaitez exister avec le même TX que l'appelant ou vous souhaitez que les intercepteurs soient appelés. Si vous n'utilisez pas le proxy, aucune de ces choses n'arrivera. – NBW

+0

@NBW: Je ne me demande pas si cela va arriver ou non. Je dis juste que cela rend votre code plus difficile à lire et augmente les chances d'invoquer la méthode de manière incorrecte, car vous pouvez le faire de plusieurs façons. Avoir un composant séparé le rend plus facile à maintenir. Votre kilométrage peut varier. – Antonio

1

Je suis pas d'accord, il est souvent utile pour la gestion des transactions pour appeler une méthode de haricot local via le conteneur. Exactement comme exemple si vous deviez appeler une méthode de bean locale dans une boucle, mieux vaut une transaction par itération que pour toutes les itérations. (à condition que la logique métier ne soit pas «tout ou rien», comme l'envoi d'une livraison ou l'émission d'actions)

+0

Cela dépend de vos exigences commerciales – deFreitas

8

L'auto-injection d'un EJB est en effet possible. La raison pour laquelle une récursion infinie ne se produira pas dans ce cas est assez simple: le conteneur n'injecte pas une instance de bean réelle du pool. Au lieu de cela, il injecte un objet proxy. Lorsque vous appelez une méthode sur le proxy injecté (foo), le conteneur obtient une instance de bean de son pool ou en crée une, s'il n'y a pas d'instances disponibles.

8

Il est possible de faire self injection. Vous devez utiliser SessionContext.

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

Oui et une autre possibilité est via une référence @EJB à un bean de son propre type ici Foo. (Voir [Comment s'auto-invoquer EJB 3.x avec (sortir) "ceci"] (http://www.adam-bien.com/roller/abien/entry/how_to_self_invoke_ejb)) – Lutz

Questions connexes