36

I have the following configuration:

  • 1 EAR on one GF containing 2 EJB-JARs with EJB components.
  • 1 WAR on another Glassfish server (=> other JVM) containing web components accessing the EJB components.

I have 2 EJB business services in each EJB-JAR of my EAR, and they are all developped like this:

@Remote
public interface ServiceAItf {
    ...
}

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

In my WAR, I access the EJB components via an explicit "InitialContext.lookup" on the remote interface.

In my EAR, I am quite confused about the best practice for injection, in terms of performance, architecture, and so on...

I have the following questions:

  • As you can see, I have declared the annotation "@Local" on the service implementation without defining the local interface. Is it correct? At least I have no error at deployment. But maybe I should use the "@LocalBean" annotation instead? I suppose that the "@LocalBean" annotation simply allows to invoke the implementation directly as a "Local" EJB, but you have to use the implementation in your code like this:

    @Stateless @Local public class ServiceBImpl implements ServiceBItf { @EJB private ServiceAImpl serviceA; ... }

  • What is the best way to inject one EJB into another one? It works like this:

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

But from what I noticed, the "serviceA" injected is the remote proxy, while it is in the same JVM within the same EAR file. So I suppose that there will be an impact on the performance. That's why I have tried to inject the service like this:

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

But it doesn't work in GF, I have the following exception:

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

I then tried to create a local interface, and the injection via the annotation "@Inject" works when both services

Even if I create a local interface like this, the service is not injected via the annotation "@Inject" but is null:

@Local
public interface ServiceALocalItf {
    ...
}

I read a lot of articles where it is highly recommended to use "@Inject" instead of "@EJB" when it is for a local invocation. That leads me to the following question: in which case the "@Local" EJB invocation is recommended (or simply used)?

After all this analysis, I come to the following conclusion:

  • For each service, I create a "@Local" and a "@Remote" interface.
  • From WAR to EJB-JAR of EAR, make a JNDI lookup to the remote interface.
  • From EJB-JAR to EJB-JAR, make an injection via "@EJB" to the local interface.
  • For two services within the same EJB-JAR, make an injection via "@Inject" to the local interface.

What do you think about it? Is it correct?

Blaise Gosselin
  • 506
  • 1
  • 5
  • 7

2 Answers2

22

As you can see, I have declared the annotation "@Local" on the service implementation without defining the local interface. Is it correct?

With EJB 3.1, the requirement for local interfaces was dropped. No need to write them unless you explicitly need them.

What is the best way to inject one EJB into another one?

Couple of things to write here:

With Java EE 6, Java Enterprise has changed. A new JSR defines a so-called managed bean (don't confuse with JSF managed beans) as a sort of minimum component that can still benefit from the container in terms of dependency injection and lifecycle management. This means: If you have a component and "just" want to use DI and let the container control its lifecycle, you do not need to use EJBs for it. You'll end up using EJBs if - and only if - you explicitly need EJB functionality like transaction handling, pooling, passivation and clustering.

This makes the answer to your question come in three parts:

  1. Use @Inject over @EJB, the concept of CDI (a) works for all managed beans (this includes EJBs) and (b) is stateful and therefore far superior over pure @EJB DI
  2. Are you sure that you need EJBs for your components?
  3. It's definitely worthwhile to have a look at the CDI documentation
Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
Jan Groth
  • 14,039
  • 5
  • 40
  • 55
  • 1
    First of all, thank you for your answer ;-) For the annotation "@Local", my question was more about the difference of behavior between the annotation "@Local" without defining the interface, and the annotation "@LocalBean"? The result will be the same: a no-interface local bean, isn't it?? In our case, we really need EJB Remote to communicate from the FRONT (on one server) to the BACK (on another server). What do you mean by "CDI is statefull"? Regarding the lifecycle management? Thanks again for your help! – Blaise Gosselin Sep 12 '11 at 06:22
-1

@Inject annotation is used for java beans(POJOs) while @EJB annotation is used for enterprise java beans. When a container inject an ejb provided by @EJB annotation to another bean it also controls that ejb's lifecycle, performs pooling for stateless beans and so on(when bean which is going to be injected is not deployed the reference will be null). If you use @Inject annotation CDI mechanism simply find and create an instance of injected resource like with new operator(if the implementation of interface which is going to be injected doesn't exist the reference will be null). You can use qualifiers with @Inject annotation to choose different implementation of injected interface.

maks
  • 5,911
  • 17
  • 79
  • 123
  • 1
    If @Inject used for POJO they must pass parameters by reference, unlike EJB wich pass parameters by value. Am I right? – umbr Sep 09 '11 at 19:09
  • 1
    what parameters are you talking about? – maks Sep 09 '11 at 19:14
  • 1
    > @Inject annotation is used for java beans(POJOs). Not entirely correct. It's used for EJB and CDI-beans injection as well. – jFrenetic Sep 09 '11 at 19:42
  • 9
    maks - sorry for downvoting, but your wording is misleading, if not false. @Inject does **not** work on POJOs, it works on **ManagedBean**s (JSR 316) and **does control the lifecyle**. The instantiation of ManagedBeans is a whole lot different than calling the new operator - you are missing the whole context part of CDI (each ManagedBean resides in a context and therefore has its lifecycle bound to the context's lifecylce)... – Jan Groth Sep 09 '11 at 20:51