The basics of using Contexts and Dependency Injection (CDI) with WebSphere Application Server

Java™ EE 6 includes a new set of features and services called Contexts and Dependency Injection (CDI). CDI relies on and provides services to other technologies introduced in Java EE 6. This article discusses the concept of dependency injection, why it is desirable, the problems it solves, how it is applied in Java EE, and its relationships with these other technologies. This content is part of the IBM WebSphere Developer Technical Journal.

Kenneth Stephen, Software Engineer, IBM

Kenneth Stephen is an application architect who has more than 20 years of experience designing and implementing applications on platforms ranging from the PC to the mainframe. He has over 10 years of experience designing and implementing applications using WebSphere Application Server and related products.



30 January 2013

Also available in Chinese

Introduction

In Java, classes can have variables (fields) that are non-primitive types. In complex applications, the type of these fields can represent complex technological solutions. For example, a class Record, can have a field of type javax.sql.DataSource, indicating that an instance of Record will be dependent on a relational datasource for its functioning. In Java EE, you would acquire an instance of this datasource by looking up an instance via JNDI. An example is shown in Listing 1.

Listing 1. Getting a reference to a dependency using JNDI
InitialContext ic = new InitialContext();  /*
                                            *  This contains references to the environment
                                            *  provided by a J2EE container
                                            */
DataSource ds = (DataSource)ic.lookup("java:comp/env/jdbc/mydbDS");

With dependency injection, you do not have to figure out how to instantiate the dependency, and you can rely on the container to do more. The example above now becomes something like Listing 2.

Listing 2. Getting a reference to a dependency using Dependency Injection
public class Myclass
{
	@Resource(name="jdbc/mydbDS" type="javax.sql.DataSource") DataSource ds;

As you can see, the code is much simpler. This is the very basic idea behind dependency injection — a simple way to declare a dependency in your code; one that enables the runtime to take over the mechanics of instantiating the dependency. This simplicity, however, is only a foundation. Built on top of this idea is a host of solutions and services that will be explored in this article.

If this were all there was to dependency injection — a simpler dependency declaration mechanism — then this wouldn't be an important topic. But this simple syntactical mechanism unlocks a whole host of capabilities and solutions to the Java EE programmer. Java EE 5 introduced something called “dependency injection,” but that particular technology is more properly called “resource injection” — it let the container inject objects that were of specific types known to the container. Dependency injection in Java EE 6 lets the container inject types defined by the application programmer.

Before delving into this topic further, a word about its pedigree. Dependency injection is a technology that has surfaced in various implementations many times before making it into the Java EE world. The Spring Framework and the Google Guice library are popular implementations. In JSR 330, an attempt was made to include these capabilities into the J2SE platform. JSR 299 is a specification that used the APIs defined in JSR 330 and added more capabilities to support Java EE needs. IBM WebSphere Application Server V8 and V8.5 (non-Liberty profiles) are fully compliant Java EE 6 containers and implement JSR 299.

Injectable types

To understand the capabilities that CDI brings to the table, and to understand its programming model, you first need to understand the interrelationships between the various specifications that make up Java EE 6 (Figure 1).

Figure 1. Relationships between Java EE 6 dependency and injection-related specifications
Figure 1. Relationships between Java EE 6 dependency and injection-related specifications

The Managed Beans specification defines services and a programming model that all the other specifications rely on and build upon. It defines some resource injection and lifecycle services; most notably, the PostConstruct and the PreDestroy annotations, which are used to indicate application developer specified lifecycle callback methods to the container.

The PostConstruct and PreDestroy annotations are also part of J2SE as of Java EE 6. This lets non-Java EE implementations in J2SE support some dependency injection functions.

The JSF specification also describes a technology known as "managed beans." These are different from the managed beans described earlier. The Java EE foundational managed beans are a generalization of the JSF one, and are not limited to web modules.

Put another way, a managed bean is a component that the container will construct and destroy (that is, manage its lifecycle).

There are three kinds of artifacts that can be injected:

  • Managed beans: EJB session beans, classes annotated with @ManagedBean, and classes that conform to the CDI rules for becoming a managed bean (see next section).
  • Java EE resources: These are resources that are referenceable from the component environment naming space.
  • Arbitrary objects that are returned by producer methods and fields.

Listing 2, above, shows an example of resource injection. Listing 3 shows an example of a CDI managed bean, which is a bean by virtue of the rules defined in the CDI spec (see next section), which supports the injection of an EJB reference.

Listing 3. Injection into a JAX-RS resource
@Path("/node")
public class NodeView
{
    @EJB(name="ejb/nodeTree", beanInterface=Nodes.class) Nodes nodeTree;
        
    @GET
    @Path("{id}")
    @Produces("application/xml")
    public Response getNode(@PathParam(value="id") int id)
    {
    	TaxonomyNode node = nodeTree.findNodeInCache(id);

Types that support injection

The kind of types and component types that can support injection (that is, objects can be injected into them) are enumerated in the Java EE 6 specification, shown in Table 1.

SpecClasses supporting injectionSupports @PostConstruct?Supports @PreDestroy?
Servletservlets, servlet filters, event listenersYesYes
JSPtag handlers, tag library event listenersYesYes
JSFscoped managed beansYesYes
JAX-WSservice endpoints, handlersYesYes
EJBbeans, interceptorsYesYes
Managed BeansClasses annotated with @ManagedBeanYesYes
CDICDI-style managed beans, decoratorsYesYes
Java EE platformmain class (static)YesNo
Java EE platformlogin callback handlerYesYes

Notice that JAX-RS resources are not listed as supporting injection, but Listing 3 shows injection working in a JAX-RS resource. This is because the container is treating it as a CDI managed bean.

Managed beans in CDI

A Java EE 6 managed bean can be declared by annotating its class with the @ManagedBean annotation. CDI specifies that a Java class qualifies as a managed bean if it is defined to be a managed bean — either by annotation, or because it is session bean, or if it conforms to all of the following rules:

  • It is not a non-static inner class.
  • It is a concrete class or is annotated @Decorator.
  • It is not an EJB component.
  • It does not implement javax.enterprise.inject.spi.Extension.
  • It has an appropriate constructor; either:
    • It has a no-argument constructor, or
    • It has a constructor annotated @Inject.

As you can see from this list, lots of classes can become managed beans. However, just because something meets the rules of being a managed bean, it doesn't get treated as one. Listing 4 shows and example of when a class gets treated like a managed bean by the container.

Listing 4. Normal vs managed bean treatment
public class PurchaseOrder
{
	@Inject User customer;	//  Container instantiates and manages instance of User
	User inventoryManager;  //  Application instantiates and manages instance of User.
	                        //  This typically happens via a new User() or equivalent.
	.
	.
}

A managed bean has bean types associated with it. These are the legal types that can be specified at the injection target for a given bean; that is, the client visible types. This can include the bean class, its super-classes, and any interfaces that it implements directly or indirectly. Thus, even though interfaces cannot be managed beans, the injection target can specify an interface as the type being injected if the bean being injected implements that interface.

In Listing 4, if User was an interface that was implemented by a concrete class called Customer, an instance of Customer could be injected into the customer variable because User is one of the bean types of Customer.

Beans can also be injected via constructor parameters, as shown in Listing 5.

Listing 5. Constructor parameter injection
public class AppContext
{
    private String userName;
        
    @Inject AppContext(User currentUser)
    {
    	userName = currentUser.getUserName();
    }

A class can specify only one of its constructors with @Inject.

Another mechanism for injection is via setter methods as shown in Listing 6. Such methods are referred to as initializer methods.

Listing 6. Parameter injection via setter method
public class AppContext
{
    private String userName;
    .
    .        

    @Inject public void setUserName(User user)
    {
    	this.userName = user.getUserName();
    }
}

Bean EL names

Managed beans are referenceable from JSPs or JSF artifacts by their EL name, which is their name in the unified EL expression language. For example, the bean shown in Listings 5 and 6 can be referenced as shown in Listing 7.

Listing 7. Referencing a managed bean in JSF
<h:outputText value="#{appContext.userName}"/>

The @Named annotation is essential to letting the bean be referenceable from JSPs and from JSF. This annotation can be used to specify an EL name as its value, but if none is specified, the container will use a default name. This name is the unqualified name of the class (for a CDI managed bean or a session bean) with the first letter changed to lowercase.

Only managed beans are referenceable in EL expressions. If a bean type is not a managed bean (for example, if it is an interface), but is a legal bean type, it does not have an EL name and will not be referenceable in an EL expression.

Built-in managed beans

The CDI specification lists some classes that Java EE containers are required to support as managed beans:

  • javax.transaction.UserTransaction permits injection of a reference to the JTA User-Transaction.
  • javax.security.Principal permits injection of a Principal representing the current caller identity.
  • javax.validation.ValidationFactory permits injection of the default Bean Validation ValidationFactory.
  • javax.validation.Validator permits injection of a Validator for the default Bean Validation ValidationFactory.

Instances of these classes do not follow the normal rules of what it means to be a CDI managed bean. Nevertheless, containers will support the instantiation, injection, and disposal of such objects just as if they were managed beans. Know that for WebSphere Application Server V8 and V8.5, APAR PM78820 needs to be applied for this to work without errors. (As of this writing, this fix is expected to be available in fixpack 6 of WebSphere Application Server V8, and fixpack 2 of WebSphere Application Server V8.5).

Packaging considerations

Developers might wish to have all their container managed classes organized into a separate JAR for organizational purposes. Java EE containers like this too: at deployment time, they are required to scan through all the deployed classes to determine which objects need to be managed by the container. The more code that needs to be scanned, the slower the deployment. To assist containers in this task, the CDI spec defines that only JAR or Java EE modules with a file called beans.xml will be scanned. Such files or modules are called bean archives. If you define CDI managed beans but you do not have a beans.xml file, the container will not scan your code for CDI related annotations, and then injection will not work.

The beans.xml file must be placed in one of these locations:

  • For a library JAR, EJB JAR, application client JAR or RAR archive, it needs to be in the META-INF directory.
  • The WEB-INF/classes directory of a WAR.
  • For a directory in the JVM classpath containing classes, the code will be scanned if the beans.xml file is located the META-INF sub-directory.

The beans.xml file can be completely empty; details on what can be put into it will be described later.

Resource bindings

Be aware that for this to work as described, APAR PM79829 has to be applied to WebSphere Application Server V8 or V8.5.

For injection of Java EE resources to work correctly into managed beans, you need the ability to specify the binding information that will map the name used in the environment context (which is specified in the bean code) to the JNDI name that points to a resource available in a container. WebSphere Application Server does this through the use of an ibm-managed-beans-bnd.xml file. Products like IBM Rational® Application Developer and IBM Rational Software Architect have easy menu options to create this file (Figure 2).

Figure 2. Creating the ibm-managed-beans-bnd.xml file in Rational Software Architect 8.5
Figure 2. Creating the ibm-managed-beans-bnd.xml file in Rational Software Architect 8.5

An example of the contents of this file is shown in Listing 8.

Listing 8. Example contents of ibm-managed-beans-bnd.xml
<managed-beans-bnd xmlns="http://websphere.ibm.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee 
		http://websphere.ibm.com/xml/ns/javaee/ibm-managed-bean-bnd_1_0.xsd"
	version="1.0">
	<managed-bean class="com.ibm.issw.taxonomy.producers.ConnectionManager">
		<resource-ref name="jdbc/supplierDB" binding-name="jdbc/ptiDS" />
		<resource-ref name="jdbc/busPartDB" binding-name="jdbc/ptiDS" />
	</managed-bean>
</managed-beans-bnd>

A better service locator

The Service Locator pattern is an application design technique that seeks to isolate application code from the details of the service implementation that it has to deal with. This enables the application to code to interfaces, and to insulate itself from details that could make it less portable or maintainable. For example, an application might want to access a service that renders an image, and this rendering service could work differently depending on the image type. Or, an application might want to access encryption or decryption services, and depending on the hardware or platform it is running on, these services might be available either natively, or via software-only libraries.

The key point here is that the Service Locator itself is part of application code. Dependency injection can provide the same level of isolation from service details, but because injection happens via the Java EE container, the programmer's job is easier. The next two sections describe how this is possible.

Qualifiers

Let’s say that you are writing a program that accesses data from two different external applications. One of them provides the data via HTTP. The other provides the data via an FTP location. You are dealing with the classes shown in Listing 9.

Listing 9. Multiple implementations of an interface
public interface Downloader
{
	//  returns the local filesystem location to the downloaded data
	public String read(String location, String userName, String password);	
}

public class WebDownloadImpl implements Downloader
{
	public String read(String location, String userName, String password)
	{
		//  Implementation details
	}	
}

public class FTPDownloadImpl implements Downloader
{
	public String read(String location, String userName, String password)
	{
		//  Implementation details
	}
}

Now, define two annotations: @Ftp and @Web. These are your "qualifiers" for the managed bean that you plan to inject (Listing 10).

Listing 10. Qualifer definition via annotations
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface Ftp
{
}

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface Web
{
}

In particular, notice the use of the @Qualifier meta-annotation. This is what tells CDI that the annotation being defined is a managed bean qualifer. Another important item to note is the RetentionPolicy. If @Retention is left off, annotations default to a RelentionPolicy of CLASS, which means that the runtime won't be aware of the qualifer being applied to a bean. Listing 11 shows how you use these qualifiers.

Listing 11. Using the defined qualifiers
@Web
public class WebDownloadImpl implements Downloader
{
        public String read(String location, String userName, String password)
        {

---
@Ftp
public class FTPDownloadImpl implements Downloader
{
        public String read(String location, String userName, String password)
        {

---
public class DatasourceReader
{
    @Inject @Ftp Downloader dinoAppReader;
    @Inject @Web Downloader modernAppReader;
    .
    .
    public void doStuff()
    {
    	String fileDino = dinoAppReader.read("location", "username", "password");
    	String fileModern = modernAppReader.read("location", "username", "password");

It is possible for multiple qualifiers to be specified at an injection point. For example, @Inject @Web @Secure modernAppReader might imply container injection of a bean which supports HTTPS (vs HTTP).

Alternatives

Let’s look at a different scenario. In production, you have some data that is being encrypted via hardware native encryption, but on your test system, you don't have this hardware and have to do this via software only. Your code looks like Listing 12.

Listing 12. Using the defined qualifiers
public interface SecureDataManager
{
	public void encrypt(String data);

---
@Default
public class NativeSecureDataManager implements SecureDataManager
{
	public void encrypt(String data);

---
@Alternative
public class SoftwareSecureDataManager implements SecureDataManager
{
        public void encrypt(String data);

@Default and @Alternative are annotations introduced by CDI. If your beans.xml looks like Listing 13, then the code in Listing 14 will instantiate an instance of SoftwareSecureDataManager into the injected field. If the beans.xml file is empty, the @Default flavor of SecureDataManager will be injected.

Listing 13. Defining the active alternative in beans.xml
<beans xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    	http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
    <alternatives>
        <class>com.ibm.issw.cdi.SoftwareSecureDataManager</class>
    </alternatives>
</beans>
Listing 14. Using the defined qualifiers
public class DataHandler
{
	@Inject private SecureDataManager sdm;

Many alternatives can be defined for a given type, but only one of them can be active at any point in a given bean archive.

Normal and pseudo scopes

Just like a variable has a known scope (that is, a period of time in a thread of execution when it is available for use), a managed bean also has a known scope. There are different kinds of scope, but broadly speaking, they fall into one of two categories: normal scopes or pseudo scopes. The difference between the two types boils down to whether instances of the managed bean are shared in the scope (normal) or whether they are not shared (pseudo).

It is important to know that Java EE components like servlets and EJBs do not have a well-defined scope. For example, servlets and stateless session beans are stateless, and therefore a client of these components cannot differentiate between one instance of the component over another. Therefore, it is meaningless to speak of the scope of such components. Stateful EJBs have client visible state, but the boundaries of "scope" of the state are not well defined because the state can be shared between any two clients by passing along the reference to the EJB. There is no begin or end to the scope, except what the application developer enforces.

Built-in scopes

The CDI spec defines some "built-in" scopes. The normal built-in scopes are @RequestScoped, @SessionScoped, @ApplicationScoped, and @ConversationScoped. The only built-in pseudo scope is @Dependent. If scope is not explicitly specified for a bean, then a default scope will take effect. In the absense of stereotypes (not covered in this article), the default scope is @Dependent.

  • The request scope is active:
    • During the service() method of a servlet, during the doFilter() method of a servlet filter, and when any ServletRequestListener or AsyncListener have been invoked by the container.
    • During any Java EE webservice invocation.
    • During a remote or async method invocation of an EJB, during an EJB timeout method, and during message delivery to a message-driven bean.
  • The session scope is active during the service() method of a servlet, during the doFilter() method of a servlet filter, and when any ServletRequestListener, AsyncListener, or HttpSessionListener has been invoked by the container. The session context is shared between all servlet requests that occur in the same HTTP session. The session context is destroyed when the HTTPSession times out, or after all HttpSessionListeners have been called, or at the very end of any request in which invalidate() was called, after all filters and ServletRequestListeners have been called.
  • The application scope is active whenever either the request or session scope is active. In addition, it is also active when a disposer method (covered later) is invoked, or during the @PreDestroy callback of any bean with @RequestScoped, @SessionScoped, or @ConversationScoped scopes. The application context is shared between all servlet requests, web service invocations, EJB remote method invocations, EJB asynchronous method invocations, EJB timeouts and message deliveries to message-driven beans that execute within the same application. The application context is destroyed when the application is shut down.

Passivating scopes

Just like stateful session beans, the container can sometimes passivate and activate some types of managed beans. Passivation-capable managed beans must be either:

  • A stateful session bean, or
  • Implement java.io.Serializable if they are a CDI managed bean.

A producer method is passivation capable if and only if all the types that it returns are passivation capable beans or are primitive types. A producer method with a return type that is declared final and does not implement serializable is not passivation capable.

An object that has been passivated by the container can contain injected dependencies, and these dependencies may be saved away or restored correctly by the container so that when the object is activated, the dependency that is restored by the container is the same instance that was injected before the passivation event. Such dependencies are called passivation capable dependencies. These objects are passivation capable dependencies:

  • All session beans
  • All beans with normal scope
  • All passivation capable beans with @Dependent scope
  • All Java EE resources.

@SessionScoped and @ConversationScoped built-in scopes are "passivating scopes". This means that all beans declared with these scopes must be passivation capable.

EJB scopes

Stateless session beans are treated as if they are @Depenedent scoped. If they are declared using any other scope, the container will report an error at deployment time. Stateful session beans can be declared using any scope. EJB singleton beans can either be declared with @ApplicationScope or @Dependent. As with regular CDI managed beans, if a scope is not declared, the EJB defaults to @Dependent.

The client proxy

Consider the managed beans shown in Listing 15.

Listing 15. Normal scoped instances
@RequestScoped
public class Employee 
{
	//....
}

public class Worker
{
	@Inject Employee manager; // manager of worker
	@Inject Employee worker;

This code will not do what the developer intended. Because @RequestScoped is a normal scope, the instance of Employee is shared between the manager and the worker variables. If the @RequestScoped were replaced by @Dependent or if it were removed (resulting in the default, in this case, of @Dependent), then the two instances for manager and worker would be different.

This behavior occurs because when a managed bean of normal scope is instantiated by the container, the injection point is set to a reference to a proxy object (the client proxy), which holds a reference to the actual managed bean that was created. The CDI spec leaves it as implementation-defined as to whether the manager and the worker variables reference the same client proxy or different ones, but it does specify that, in both cases, the same managed bean should be referenced by those client proxy or proxies. A client proxy is actually necessary to solve the problem of how to handle situations where (for example) a request-scoped bean is injected into a session scoped bean.

Figure 3. Active scoped instances during two concurrent requests
Figure 3. Active scoped instances during two concurrent requests

In Figure 3, you have two requests sharing the same session and being processed at the same time, where there is a session scoped managed bean (S1) holding references to an injected request scoped managed bean (R1 or R2). While the first request is being processed, the reference to the request scoped object must resolve to R1, and when the second request is being processed, it must resolve to R2. This is impossible, unless there is a level of indirection — where the reference from S1 goes to a container managed object that is capable of switching out the reference to the right request scoped object as needed.

Figure 4. The role of the client proxy
Figure 4. The role of the client proxy

Technically, the references to the contextual instance of the bean are resolved at run time by the container from the context. This behavior is described by the spec; to quote it: "Every time a method of the bean is invoked on a client proxy, the client proxy must obtain a contextual instance of the bean."

The other benefit to having a client proxy is that it enables the container to deal with circular dependencies. Consider the beans shown in Listing 16.

Listing 16. Mutually dependent managed beans
public class Person
{
    @Inject private House home;
}

---

public class House
{
    private Person owner;
        
    @Inject public House(Person owner)
    {
        this.setOwner(owner);
    }
    //...
}

An attempt to inject @Person or @House into a bean will lead to a StackOverflowException in WebSphere Application Server V8 or V8.5, which is caused by the circular dependency. Know, however, that the scope of these two beans have not been specified and therefore they have defaulted to @Dependent. If you change Person to be @RequestScoped, the injection will work correctly because of the presence of a client proxy. Indeed the spec requires, in any chain of circular dependencies, that if at least one of the dependencies is a normal scoped bean, then a compliant container should support injection of those beans.


Contexts

Take a look at Figure 4 again. The client proxy reference to the R1 and R2 objects are happening at the same time, but in different threads. For this to be possible, the container has to maintain contextual information about what is happening in each thread. In fact, for each kind of scope, the container maintains contexts for all injected objects so that when a thread of execution follows a reference to an injected object, the container will hand it the right one.

For normal scopes, contexts will propagate over all local synchronous method invocations. Conversely, contexts will not propagate over remote method invocations, or asynchronous events (like EJB timer service timeouts).

Be aware that in WebSphere Application Server, the context does propagate across remote EJB invocations if the invoked session bean is present locally. This happens because in WebSphere Application Server, the container optimizes things so that remote method invocations in the same JVM happen on the same thread, and, in such cases, the contextual reference will already be active and doesn't need to be created.

Producers and disposers

One mechanism of producing injectable objects that have not yet been discussed is to use methods as a source for injectable objects. This will even let you inject objects whose classes don't conform to the rules of CDI managed beans. However, in such cases, these classes cannot themselves be targets of injection. And since the container does not manage the lifecycle of such objects, methods annotated with @PostConstruct or @PreDestroy will not be invoked by the container.

You would use producer methods if:

  • You need injection on objects that are not managed bean instances.
  • The concrete type of the objects to be injected may vary at run time.
  • The objects require some custom initialization that is not performed by the bean constructor.

Listing 17 shows an example, adapted from the CDI spec, of a producer method that returns different bean instances depending on method logic.

Listing 17. Producer that returns programmatically determined type
@SessionScoped
public class PaymentStrategyProducer implements Serializable {
	private PaymentStrategyType paymentStrategyType;
	public void setPaymentStrategyType(PaymentStrategyType type) {
		paymentStrategyType = type;
	}
	@Produces 
	@SessionScoped /*
	                *  This must be a scope that allows one to get to the same
	                *  contextual reference of the bean (PaymentStrategyProducer)
	                *  that the setPaymentStrategyType method was invoked on. For
	                *  example, if the bean was @SessionScoped, then the method 
	                *  could be @RequestScoped
	                */
	PaymentStrategy getPaymentStrategy(
			@CreditCard PaymentStrategy creditCard,
			@Cheque PaymentStrategy cheque,
			@Online PaymentStrategy online) {
		switch (paymentStrategyType) {
			case CREDIT_CARD: return creditCard;
			case CHEQUE: return cheque;
			case ONLINE: return online;
			default: throw new IllegalStateException();
		}
	}
}

A producer method can be static or non-static. If the containing bean is a session bean, then the non-static producer methods must be business methods of the EJB. When the container determines that a producer method needs to be invoked, the sequence of events depends on whether the method is static or not. For static methods, the method is directly invoked. For non-static methods, the container must first instantiate the managed bean if a contextual instance of the bean does not exist.

If a bean with producer methods has a passivating scope, then all the parameters injected into the producer methods must be passivation-capable dependencies. In the example, above, the classes implementing PaymentStrategy for the qualifiers of @CreditCard, @Cheque, and @Online, need to be serializable. Needless to say, if the producer method uses a scope that is a passivating scope, then the return type should also be passivation capable. In the example above, this means that the PaymentStrategy interface needs to extend Serializable.

A disposer method serves the opposite purpose: to perform a programmer-controlled cleanup of resources and beans that have been injected via a producer method. Just like producer methods, the methods can be static or non-static. For a session bean, the disposer method must be a business method of the EJB.

The container will match up disposer methods to producer methods defined in the same class. It does this by comparing the bean types returned by the producer methods to the bean types declared as being disposed by the disposer method. A disposer method might get matched to multiple producer methods. Disposer methods are automatically invoked by the container when it starts the process of destroying objects created by producer methods (Listing 18).

Listing 18. Producer with paired Disposer method
public class ConnectionManager
{
    @Resource(name="jdbc/supplierDB", authenticationType=AuthenticationType.CONTAINER, 
    		type=DataSource.class, shareable=true) DataSource suppDB;
            
    @Produces @Supplier @RequestScoped
    public Connection getSupplierConnection()
    {
        System.out.println("Producer method called");
        try{
            return suppDB.getConnection();
        }catch(SQLException e){
            throw new RuntimeException(e);
        }
    }
    public void cleanupSupplierConnections(@Disposes @Supplier Connection c)
    {
        System.out.println("Disposer method called");
        try{
            c.close();
        }catch(SQLException e){
            throw new RuntimeException(e);
        }
    }

A producer method can also be annotated with @Named so that it can be referenced in an EL expression. The default EL name of the returned bean is the producer method name.

Conclusion

This article covered some very basic concepts and constructs made available to WebSphere Application Server V8 and V8.5 developers via the CDI specification. This specification also has more advanced features, which will be covered in a later article.

Acknowledgements

The author thanks Eric Covener, Joseph Bergmark, and Paul Glezen (all of IBM) who reviewed this article and provided insightful feedback.

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=856644
ArticleTitle=The basics of using Contexts and Dependency Injection (CDI) with WebSphere Application Server
publish-date=01302013