Wednesday, March 18, 2015

Contexts and Dependency Injection (CDI) - Eager Extension

CDI does not provide eager extensions out of the box. Even though there is @ApplicationScoped that is intended to work in a similar way to eager instantiation - It does not behave in the specified fashion. 

I am going to describe how to use CDI extensions to get eagerly instantiated beans following the CDI lifecycle, inside the container. I have used this in Wildfly 8.0. 


Step 1: First, write the @Eager Annotation
 package me.sumithpuri.test.cdi.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.inject.Qualifier;
@Qualifier @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) public @interface Eager { }

Step 2: Next, develop the Eager Extension to parse the Annotations.
 package me.sumithpuri.test.cdi.extension;  
import java.util.ArrayList; import java.util.List; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Observes; import javax.enterprise.inject.spi.AfterDeploymentValidation; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.ProcessBean; import me.sumithpuri.test.cdi.annotation.Eager;
public class EagerExtension implements Extension {
private List<Bean<?>> eagerBeansList = new ArrayList<Bean<?>>(); public <T> void collect(@Observes ProcessBean<T> event) {
if (event.getAnnotated().isAnnotationPresent(Eager.class) && event.getAnnotated().isAnnotationPresent(ApplicationScoped.class)) { System.out.println("debug: found an eager annotation"); eagerBeansList.add(event.getBean()); } }
public void load(@Observes AfterDeploymentValidation event, BeanManager beanManager) {
for (Bean<?> bean : eagerBeansList) { System.out.println("debug: eager instantiation will be performed - " + bean.getBeanClass()); // note: toString() is important to instantiate the bean beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean)).toString(); } } }

Step 3: Next, configure the extension, using this single line of code, placed inside META-INF/services/javax.enterprise.inject.spi.Extension
 me.sumithpuri.test.cdi.extension.EagerExtension  

Step 4: Develop other parts of the application 
You can refer to the attached code to develop other parts of the application to test CDI (@Eager)

You may download the code from here. Also, note that even though all lifecycle methods are performed such @PostConstruct, @PreDestroy, etc. - no @Inject is being performed. My assumption is that we have to write another extension to perform this. My request to the CDI creators to provide an @Eager out of the box, so that it can help to develop (and sometime help in test) applications where Dependency Injection can be performed outside of Servlets, Web Services, etc.

[credits to: http://ovaraksin.blogspot.in/2013/02/eager-cdi-beans.html]

No comments: