web-dev-qa-db-fra.com

@Inject, @EJB, @Local, @Remote, @LocalBean, etc ...: confus?

J'ai la configuration suivante:

  • 1 EAR sur un GF contenant 2 EJB-JAR avec des composants EJB.
  • 1 WAR sur un autre serveur Glassfish (=> autre JVM) contenant des composants Web accédant aux composants EJB.

J'ai 2 services commerciaux EJB dans chaque EJB-JAR de mon EAR, et ils sont tous développés comme ceci:

@Remote
public interface ServiceAItf {
    ...
}

@Stateless
@Local
public class ServiceAImpl implements ServiceAItf {
    ...
}

Dans ma GUERRE, j'accède aux composants EJB via un "InitialContext.lookup" sur l'interface distante.

Dans mon EAR, je suis assez confus quant aux meilleures pratiques d'injection, en termes de performances, d'architecture, etc.

J'ai les questions suivantes:

  • Comme vous pouvez le voir, j'ai déclaré l'annotation "@Local" sur l'implémentation du service sans définir l'interface locale. Est-ce correct? Au moins, je n'ai aucune erreur lors du déploiement. Mais je devrais peut-être utiliser le "@LocalBean" annotation à la place? Je suppose que le "@LocalBean" l'annotation permet simplement d'invoquer l'implémentation directement en tant que "Local" EJB, mais vous devez utiliser l'implémentation dans votre code comme ceci:

    @Stateless @Local classe publique ServiceBImpl implémente ServiceBItf {@EJB private ServiceAImpl serviceA; ...}

  • Quelle est la meilleure façon d'injecter un EJB dans un autre? Cela fonctionne comme ceci:

    @Stateless @Local classe publique ServiceBImpl implémente ServiceBItf {@EJB private ServiceAItf serviceA; ...}

Mais d'après ce que j'ai remarqué, le "serviceA" injecté est le proxy distant, alors qu'il se trouve dans la même JVM dans le même fichier EAR. Je suppose donc qu'il y aura un impact sur les performances. C'est pourquoi j'ai essayé d'injecter le service comme ceci:

@Stateless
@Local
public class ServiceBImpl implements ServiceBItf {
    @Inject
    private ServiceAItf serviceA;
    ...
}

Mais cela ne fonctionne pas dans GF, j'ai l'exception suivante:

WELD-001408 Unsatisfied dependencies for type [...] ...

J'ai ensuite essayé de créer une interface locale, et l'injection via l'annotation "@Inject" fonctionne lorsque les deux services

Même si je crée une interface locale comme celle-ci, le service n'est pas injecté via l'annotation "@Injecter" mais est nul:

@Local
public interface ServiceALocalItf {
    ...
}

J'ai lu beaucoup d'articles où il est fortement recommandé d'utiliser "@Injecter" au lieu de "@EJB" quand c'est pour une invocation locale. Cela m'amène à la question suivante: dans quel cas le "@Local" L'invocation EJB est recommandée (ou simplement utilisée)?

Après toute cette analyse, j'arrive à la conclusion suivante:

  • Pour chaque service, je crée un "@Local" et un "@Éloigné" interface.
  • De WAR à EJB-JAR d'EAR, effectuez une recherche JNDI sur l'interface distante.
  • De EJB-JAR à EJB-JAR, faites une injection via "@EJB" à l'interface locale.
  • Pour deux services au sein d'un même EJB-JAR, effectuez une injection via "@Inject" sur l'interface locale.

Qu'est-ce que tu en penses? Est-ce correct?

36
Blaise Gosselin

Comme vous pouvez le voir, j'ai déclaré l'annotation "@Local" sur l'implémentation du service sans définir l'interface locale. Est-ce correct?

Avec EJB 3.1, l'exigence d'interfaces locales a été supprimée. Pas besoin de les écrire sauf si vous en avez explicitement besoin.

Quelle est la meilleure façon d'injecter un EJB dans un autre?

Quelques choses à écrire ici:

Avec Java EE 6, Java Enterprise a changé. Un nouveau JSR définit un soi-disant bean géré (ne pas confondre avec les beans gérés JSF) comme une sorte de composant minimum qui peut toujours bénéficier du conteneur en termes d'injection de dépendances et de gestion du cycle de vie. Cela signifie: si vous avez un composant et "juste" voulez utiliser DI et laisser le conteneur contrôler son cycle de vie, vous n'avez pas besoin d'utiliser des EJB pour cela. Vous finirez par utiliser des EJB si - et uniquement si - vous avez explicitement besoin de fonctionnalités EJB telles que la gestion des transactions, la mise en commun, la passivation et le clustering.

Cela rend la réponse à votre question en trois parties:

  1. Utilisez @Inject sur @EJB, le concept de CDI (a) fonctionne pour tous les beans gérés (cela inclut les EJB) et (b) est dynamique et donc bien supérieur à pur @EJB DI
  2. Êtes-vous sûr d'avoir besoin d'EJB pour vos composants?
  3. Il vaut vraiment la peine de jeter un œil au CDI documentation
22
jan groth

@Inject l'annotation est utilisée pour Java beans (POJO) tandis que @EJB l'annotation est utilisée pour l'entreprise Java beans. Lorsqu'un conteneur injecte un ejb fourni par @EJB annotation à un autre bean, il contrôle également le cycle de vie d'ejb, effectue la mise en pool des beans sans état, etc. (lorsque le bean qui va être injecté n'est pas déployé, la référence sera nulle). Si tu utilises @Inject le mécanisme CDI d'annotation recherche et crée simplement une instance de ressource injectée comme avec un nouvel opérateur (si l'implémentation de l'interface qui va être injectée n'existe pas la référence sera nulle). Vous pouvez utiliser des qualificatifs avec @Inject annotation pour choisir une implémentation différente de l'interface injectée.

0
maks