The Hollywood Principle

Tutorial - Introduction to CDI - Contexts and Dependency Injection for Java EE (JSR 299) - Part 3

 

The Lifecycle of a CDI container

Let's look at an easy scenario with a CDI container inside a plain Servlet engine such as Apache Tomcat. If a WebApplication gets started, a ServletFilter will automatically also start your CDI container which will firstly register all CDI-Extensions available on the ClassPath and then start with the class scanning. All ClassPath entries with a META-INF/beans.xml will be scanned and all classes will be parsed and stored as ‘Managed Bean’ (interface Bean<T>) meta-information inside the CDI container. The reason for scanning this information on startup is to: first. detect errors early and second, vastly improve the performance at runtime.

To be able to handle all the CDI Scopes correctly, a CDI container simply uses standard Servlet callbacks like ServletRequestListener and HttpSessionListener.

Standard scopes

JSR-299 defines the most important scopes to build classic web applications:

  • @ApplicationScoped
  • @SessionScoped
  • @ConversationScoped
  • @RequestScoped

Those scopes are meta-annotated as @NormalScope which means they have a well-defined lifecycle.

Beside those, there is another non-normal scope: @Dependent. If a class doesn't have any explicit CDI scope annotation or is explicitly annotated with @Dependent, an instance will be created for each and every InjectionPoint and will share the lifecycle of the contextual instances they get injected into.

An example: if a @Dependent MySecurityHelper is injected in a @RequestScoped MyBackingBean, then the MySecurityHelper instance will be destroyed along with the MyBackingBean instance at the end of the request. If you @Inject the MySecurityHelper into a @SessionScoped UserSettings object, it will also be treated as @SessionScoped.

Qualifiers

If an application needs multiple implementations of one and the same interface, this previously has been solved by giving them different names. The problem with this approach is that this string-based solution is not typesafe and can easily lead to ClassCastExceptions. The CDI specification introduced a typesafe way to achieve the same result with the @Qualifier meta-annotation.

A small sample: An application needs to access two different databases with JPA. Thus we need two different EntityManagers. To distinguish between those, we just create two @Qualifier annotations @CustomerDb and @AdminDb (in analogue):

@Target( { TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
@Qualifier
public @interface CustomerDb {}

Those Qualifiers can now easily be used to inject the appropriate EntityManager:

public @ApplicationScoped class MyService {
 private @Inject @CustomerDb EntityManager customerEm;
 private @Inject @AdminDb EntityManager adminEm;
 ...

If no Qualifier is being used, the pre-defined @Default Qualifier will be assumed.

 

Pages

Mark Struberg
Mark Struberg
Peter Muir
Peter Muir

What do you think?

JAX Magazine - 2014 - 06 Exclucively for iPad users JAX Magazine on Android

Comments

Latest opinions