Java EE CDI Dependency Injection (@Inject) tutorial
Introduction
Java EE CDI makes primarily use of the @Inject annotation in order to perform Dependency Injection of managed beans into other container managed resources. In this tutorial we will cover the different available strategies to perform dependency injection in a CDI environment.
This tutorial considers the following environment:
- JDK 1.7.0.21
- Weld 1.1.10
Weld is the CDI reference implementation
Constructor dependency injection
public class SomeBean { private final Service service; @Inject public SomeBean(Service service){ this.service = service; } }
When the CDI container is instantiating a bean of type SomeBean it will look for the default (no arguments) constructor and use it to create the bean instance. The exception to this rule is when we have another constructor annotated with @Inject. If this is the case, the container will use the annotated constructor instead and will inject the dependencies that are passed as constructor arguments.
In the above sample it will fetch a Service instance and inject into the SomeBean annotated constructor.
Field dependency injection
public class SomeBean { @Inject private Service service; }
In this case when the container is initializing a bean of type SomeBean it will inject the correct Service bean into the field, even if it is private, without the need of any setter method.
Initializer methods dependency injection
public class SomeBean { private Service service; @Inject public void setService(Service service) { this.service = service; } }
In this case when the container is initializing a bean of type SomeBean it will call all methods that are annotated with @Inject and inject the dependencies as method arguments.
The @Any qualifier
In order to provide fully loosely coupled applications we usually inject interfaces into managed resources. What if we have multiple bean implementations for a given interface? We may inject them all into a managed bean using the @Any qualifier along with the CDI Instance interface:
public class SomeBean { @Inject public void listServiceImplementations( @Any Instance<Service> serviceList) { for(Service service : serviceList){ System.out.println(service.getClass().getCanonicalName()); } } }
The @Any qualifier instructs the container that this injection point may be satisfied by any available dependency, so the container injects them all. If we have multiple interface implementations and we inject only one - without making any kind of disambiguation - the container will complain and fail to initialize the component. We will see about dependency disambiguation in other tutorial.
Injection into Producer methods
Producer method arguments may also be injected by the CDI container. Please see Java EE CDI Producer methods tutorial.
CDI Proxies
This tutorial will not be complete of we didn't also cover the CDI proxying mechanism. When we inject a managed bean that is created in a scope different than @Dependent - into another managed resource - the CDI container does not inject a direct reference to the injected bean.
For CDI bean scopes please see Java EE CDI bean scopes.
Why does CDI uses proxies? Because if direct bean references were injected it would create problems like thread-safety or concurrent access to managed beans.
Imagine that a Session scoped bean is injected into an Application scoped bean. Since application scoped beans are shared among all clients, if more than one client accessed the application scoped bean simultaneously it would exist a high risk of one client accessing the other's directly referenced session scoped bean.
To work around this problem CDI creates proxies and inject the proxies instead into the injection points. The proxy will then handle the calls to the injected beans and forward the calls to the correct bean instance.
The proxies created by CDI extend the class of the injected bean. Imagine the following scenario:
@SessionScoped public class Service { public void doWork() { System.out.println("Working..."); } } @ApplicationScoped public class SomeBean { @Inject private Service service; public void test(){ service.doWork(); } }
CDI will inject a proxy to the session scoped bean into the application scoped bean. Every call to the session scoped bean will go through the proxy that in turn will redirect the call to the correct session bean instance: the one that belongs to the current HTTP request session.
CDI creates proxies by extending the bean class and overriding all non-private methods. A mere representative illustration of the proxy could be like the following:
public class Service$Proxy$_$$_WeldClientProxy extends Service { @Override public void doWork() { Service instance = // ... resolve bean instance instance.doWork(); } }
Since CDI proxies are created by extending the bean class there are some CDI restrictions that should come into your mind when we talk about non-dependent bean scopes:
- CDI can not inject primitive types
- The bean class must have a non-private default constructor
- The bean class must not be final and must not have any final methods