Dependency Injection In Java and CDI

Dependency injection(DI) is one of the key techniques that enables a class or module to be injected into another, which also enables us to apply the principal of seperation of concerns via enabling a way of entity association and making wiring easy.

Along with Java EE 5, dependency injection was made of a part of the specification with JSR 250 (Common Annotations). For basic usages of injection, it has been a good start for Java platform especially with the annotations; @ManagedBean and @Resource.

Since Java EE 6, JSR 330 (Dependency Injection for Java) was introduced and the frequently used annotations like @Inject and @Named were made available. And ultimately, Contexts and Dependency Injection was also introduced with Java EE 6 which is built on top of JSR 330. Comparing to DI, CDI additionally provides an easy to use event mechanism, decorators and interceptors to add functionality to beans.

Since Java EE 5 with the EJB 3.0 specification, Java EE also provides injection for EJBs which are container managed beans. So, while CDI aims at dependency injection, EJB adds container services to container managed beans. Since EJB 3.1, EJB components are built on top of CDI and provides container services such as transaction management.

Here is the evolution of DI in Java EE paltform:
JSR 250 - EE5 (Common Annotations) - @ManagedBean and @Resource
JSR 220 - EE5 (EJB 3.0) - @Stateless, @Stateful, @Singleton
JSR 330 - EE6 (DI    1.0) - @Inject and @Named
JSR 314 - EE6 (JSF 2.0) - @ManagedBean, @ManagedProperty
JSR 299 - EE6 (CDI 1.0)
JSR 318 - EE6 (EJB 3.1) - @Stateless, @Stateful, @Singleton
JSR 344 - EE7 (JSF 2.2) - @ManagedBean, @ManagedProperty
JSR 346 - EE7 (CDI 1.1) 
JSR 345 - EE7 (EJB 3.2) - @Stateless, @Stateful, @Singleton
JSR 372 - EE8 (JSF 2.3) - @ManagedBean, @ManagedProperty (deprecated)
JSR 365 - EE8 (CDI 2.0) 

Confusing when to use which?
  • If you are in an environment not having CDI and not using JSF, then you can use JSR 250 Common annotations
    • Declare beans with @javax.annotation.ManagedBean
    • Inject beans with @javax.annotation.Resource
  • If you are developing a JSF application and your environment is not CDI-compatible, such as a servlet container, then
    • Declare beans with @javax.faces.bean.ManagedBean
    • Inject JSF beans with @javax.faces.bean.ManagedProperty
    • Inject EJBs with @javax.ejb.EJB
    • Along with JSF 2.3, JSF managed beans is deprecated in favour of CDI.
  • If your environment is CDI-compatible then 
    • Declare beans with @javax.inject.Named and/or scope annotations
    • Inject beans with @javax.inject.Inject
    • Prefer CDI-scoped annotations instead of JSF-scoped annotations
    • You can inject EJBs(local only) with @javax.ejb.EJB into CDI beans
    • You can inject CDI beans into EJBs

What is a Managed Bean, Context, LifeCycle, Scope ? 

First, let's cope with the confusion about the terms context and scope.
Context is a term that tells about the environment on which our beans are working. So, it can be thought as a container for beans.

For example, if we are working on a servlet environment that is servlet container, then our context is Servlet Context; and generally speaking a kind of facade is out there named ServletContext that is a helper for the services from the servlet container.
If we are working on a JSF application, then we can talk about the FacesContext and that connects us to the container specific services.
Or EJBContext if we are working on EJBs which is extended by SessionContext, EntityContext and so on.

Then what is scope ?
The lifecycle of a bean in a context is determined with scopes. 
Meaning that, scope defines the lifecycle of a bean in a context which is a container for that bean. 

Here is an example:
A context like FacesContext serves as a container for the JSF beans.
In the FacesContext, beans are kept grouped by its scopes.
Here is a real world example to understand it better:

ViewScoped beans in the FacesContext:
Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
ViewScopedCustomBean bean = (ViewScopedCustomBean) viewMap.get("viewScopedCustomBean");

SessionScoped beans in the FacesContext:
Map<String, Object> sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
SessionScopedCustomBean bean = (SessionScopedCustomBean) sessionMap.get("sessionScopedCustomBean");

Meaning that, if we are using the term CONTEXT, then generally we try to tell something environmental things or referring the container itself.
And in Java, generally, there will be a AbcContext class that is a facade kind of helper connecting us to the environmental services of the container.

Okay, then the next term to understand is managed bean
The notion managed bean is defined in the the Managed Beans Specification in Java EE 6(JSR-316). A managed bean(container-managed object) is a Java Bean that is managed by the container with container services, lifecycle callbacks and interceptors.

A managed bean is bounded to a context generally with dependency injection and is called contextual instance.
A contextual instance is available to other objects in the context it's bounded.
A contextual instance has a lifecycle declared with a scope in the context and that is managed by the container of the context.

Simply, lifecycle is the life of the managed bean inside the context 
and the container automatically creates the instance when needed and destroy it at the end of the context.

CDI Benefits

- Binding objects to lifecycle contexts
- Allowing contextual objects to be used within JSF or JSP pages via the Unified Expression Language (EL)
- Associating with the interceptors and decorators
- Conversation context is a new web context introduced with CDI in addition to the contexts Request, Session and Application which are defined in Servlet specification.


Injectable Objects

- EJB 3 session beans
- Managed beans
- Java EE resources

Along with CDI 2.0, the specification splits Java SE and Java EE features.


Declaring and observing events

We can define an annotation pointing an event and firing an event with this annotation as below:
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface OpenEvent

We can inject the event into a managed bean and fire it as following:
@Inject @OpenEvent Event openEvent;
...
openEvent.fire(car);

And eventually, we can observe the event as following:
public void onOpen(@Observes @OpenEvent Car car) {
    System.out.println(car.getName() + " is opened.");
}

You can find code samples for using di and cdi annotations on my github page.
https://github.com/erolhira/javaee-samples/tree/master/javaee8-samples  

References

http://www.cdi-spec.org/learn/
https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html
https://docs.jboss.org/cdi/learn/userguide/CDI-user-guide.html

Yorumlar

Popular

Java 14 New Features

Pretenders, Contenders and Liars

Java 12 New Features