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

Blaise Gosselin picture Blaise Gosselin · Sep 9, 2011 · Viewed 31.9k times · Source

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?

Answer

jan groth picture jan groth · Sep 10, 2011

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