Named bean scopes

Just like JSF managed beans, CDI named beans are scoped. This means that CDI beans are contextual objects. When a named bean is needed, either because of injection or because it is referred from a JSF page, CDI looks for an instance of the bean in the scope it belongs to and injects it into the dependent code. If no instance is found, one is created and stored in the appropriate scope for future use. The different scopes are the context in which the bean exists.

The following table lists the different valid CDI scopes:

Scope

Annotation

Description

Request

@RequestScoped

request-scoped beans are shared through the duration of a single request. A single request could refer to an HTTP request, an invocation to a method in an EJB, a web service invocation, or sending a JMS message to a message-driven bean.

Conversation

@ConversationScoped

The conversation scope can span multiple requests but is typically shorter than the session scope.

Session

@SessionScoped

session-scoped beans are shared across all requests in an HTTP session. Each user of an application gets their own instance of a session scoped bean.

Application

@ApplicationScoped

application-scoped beans live through the whole application lifetime. Beans in this scope are shared across user sessions.

Dependent

@Dependent

dependent-scoped beans are not shared; any time a dependent scoped bean is injected, a new instance is created.

 

As we can see, CDI includes most scopes supported by JSF, and also adds a couple of its own. CDI's request scope differs from JSF's request scope, in which a request does not necessarily refer to an HTTP request; it could simply be an invocation on an EJB method, a web service invocation, or sending a JMS message to a message-driven bean.

The conversation scope does not exist in JSF. This scope is similar to JSF's flow scope, since it is longer than the request scope but shorter than the session scope, and typically spans three or more pages. Classes wishing to access a conversation-scoped bean must have an instance of javax.enterprise.context.Conversation injected. At the point where we want to start the conversation, the begin() method must be invoked on this object. At the point where we want to end the conversation, the end() method must be invoked on it.

CDI's session scope behaves just like its JSF counterpart. The lifecycle of session-scoped beans are tied to the life of an HTTP session.

CDI's application scope also behaves just like the equivalent scope in JSF. Application-scoped beans are tied to the life of an application. A single instance of each application-scoped bean exists per application, which means that the same instance is accessible to all HTTP sessions.

Just like the conversation scope, CDI's dependent scope does not exist in JSF. New dependent scope beans are instantiated every time it is needed; usually when it is injected into a class that depends on it.

Suppose we wanted to have a user enter some data that would be stored in a single named bean, but that bean has several fields. Therefore, we would like to split the data entry into several pages. This is a fairly common situation and one that was not easy to handle using previous versions of Java EE (JSF 2.2 added Faces Flows to solve this problem; refer to Chapter 2, JavaServer Faces ), or the servlet API for that matter. The reason this situation was not easy to manage using those technologies is that you could either put a class in the request scope, in which case the class would be destroyed after every single request, losing its data in the process, or in the session scope, in which the class would stick around in memory long after it was needed. For cases like this, CDI's conversation scope is a good solution:

package net.ensode..javaee8book.conversationscope.model; 
 
import java.io.Serializable; 
import javax.enterprise.context.ConversationScoped; 
import javax.inject.Named; 
import org.apache.commons.lang3.builder.ReflectionToStringBuilder; 
 
@Named 
@ConversationScoped 
public class Customer implements Serializable { 
 
    private String firstName; 
    private String middleName; 
    private String lastName; 
    private String addrLine1; 
    private String addrLine2; 
    private String addrCity; 
    private String state; 
    private String zip; 
    private String phoneHome; 
    private String phoneWork; 
    private String phoneMobile; 
 
    public String getAddrCity() { 
        return addrCity; 
    } 
 
    public void setAddrCity(String addrCity) { 
        this.addrCity = addrCity; 
    } 
 
    public String getAddrLine1() { 
        return addrLine1; 
    } 
 
    public void setAddrLine1(String addrLine1) { 
        this.addrLine1 = addrLine1; 
    } 
 
    public String getAddrLine2() { 
        return addrLine2; 
    } 
 
    public void setAddrLine2(String addrLine2) { 
        this.addrLine2 = addrLine2; 
    } 
 
    public String getFirstName() { 
        return firstName; 
    } 
 
    public void setFirstName(String firstName) { 
        this.firstName = firstName; 
    } 
 
    public String getLastName() { 
        return lastName; 
    } 
 
    public void setLastName(String lastName) { 
        this.lastName = lastName; 
    } 
 
    public String getMiddleName() { 
        return middleName; 
    } 
 
    public void setMiddleName(String middleName) { 
        this.middleName = middleName; 
    } 
 
    public String getPhoneHome() { 
        return phoneHome; 
    } 
 
    public void setPhoneHome(String phoneHome) { 
        this.phoneHome = phoneHome; 
    } 
 
    public String getPhoneMobile() { 
        return phoneMobile; 
    } 
 
    public void setPhoneMobile(String phoneMobile) { 
        this.phoneMobile = phoneMobile; 
    } 
 
    public String getPhoneWork() { 
        return phoneWork; 
    } 
 
    public void setPhoneWork(String phoneWork) { 
        this.phoneWork = phoneWork; 
    } 
 
    public String getState() { 
        return state; 
    } 
 
    public void setState(String state) { 
        this.state = state; 
    } 
 
    public String getZip() { 
        return zip; 
    } 
 
    public void setZip(String zip) { 
        this.zip = zip; 
    } 
 
    @Override 
    public String toString() { 
        return ReflectionToStringBuilder.reflectionToString(this); 
    } 
}  

We declare that our bean is conversation scoped by decorating it with the @ConversationScoped annotation. Conversation-scoped beans also need to implement java.io.Serializable. Other than those two requirements, there is nothing special about our code; it is a simple JavaBean with private properties and corresponding getter and setter methods.

We are using the Apache commons-lang library in our code to easily implement a toString() method for our bean. commons-lang has several utility methods like this that implement frequently needed, tedious to code functionality. commons-lang is available in the central Maven repositories and at http://commons.apache.org/lang.

In addition to having our conversation-scoped bean injected, our client code must also have an instance of javax.enterprise.context.Conversation injected, as illustrated in the following example:

package net.ensode.javaee8book.conversationscope.controller; 
 
import java.io.Serializable; 
import javax.enterprise.context.Conversation; 
import javax.enterprise.context.RequestScoped; 
import javax.inject.Inject; 
import javax.inject.Named; 
import net.ensode.javaee8book.conversationscope.model.Customer; 
 
@Named 
@RequestScoped 
public class CustomerInfoController implements Serializable { 
 
    @Inject 
    private Conversation conversation; 
    @Inject 
    private Customer customer; 
 
    public String customerInfoEntry() { 
        conversation.begin(); 
        System.out.println(customer); 
        return "page1"; 
    } 
 
    public String navigateToPage1() { 
        System.out.println(customer); 
        return "page1"; 
    } 
 
    public String navigateToPage2() { 
        System.out.println(customer); 
        return "page2"; 
    } 
 
    public String navigateToPage3() { 
        System.out.println(customer); 
        return "page3"; 
    } 
 
    public String navigateToConfirmationPage() { 
        System.out.println(customer); 
        conversation.end(); 
        return "confirmation"; 
    } 
} 

Conversations can be either long-running or transient. Transient conversations end at the end of a request, while long-running conversations span multiple requests. In most cases, we use long-running conversations to hold a reference to a conversation-scoped bean across multiple HTTP requests in a web application.

A long-running conversation starts when the begin() method is invoked in the injected Conversation instance, and it ends when we invoke the end() method on the same object.

JSF pages simply access our CDI beans as usual:

<?xml version='1.0' encoding='UTF-8' ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:h="http://xmlns.jcp.org/jsf/html"> 
    <h:head> 
        <title>Customer Information</title> 
    </h:head> 
    <h:body> 
        <h3>Enter Customer Information (Page 1 of 3)</h3> 
        <h:form> 
            <h:panelGrid columns="2"> 
                <h:outputLabel for="firstName" value="First Name"/> 
                <h:inputText id="firstName" value="#
{customer.firstName}"/> <h:outputLabel for="middleName" value="Middle
Name"/> <h:inputText id="middleName" value="#
{customer.middleName}"/> <h:outputLabel for="lastName" value="Last Name"/> <h:inputText id="lastName" value="#
{customer.lastName}"/> <h:panelGroup/> <h:commandButton value="Next" action="#
{customerInfoController.navigateToPage2}"/> </h:panelGrid> </h:form> </h:body> </html>

As we navigate from one page to the next, we keep the same instance of our conversation-scoped bean; therefore, all user entered data remains. When the end() method is called on our conversation bean, the conversation ends and our conversation-scoped bean is destroyed.

Keeping our bean in the conversation scope simplifies the task of implementing wizard-style user interfaces, where data can be entered across several pages:

In our example, after clicking the Next button on the first page, we can see our partially populated bean in the application server log:

INFO: net.ensode..javaee8book.conversationscope.model.Customer@6e1c51b4[firstName=Daniel,middleName=,lastName=Jones,addrLine1=,addrLine2=,addrCity=,state=AL,zip=<null>,phoneHome=<null>,phoneWork=<null>,phoneMobile=<null>] 

At this point, the second page in our simple wizard is displayed:

When we click Next, we can see that additional fields are populated in our conversation-scoped bean:

INFO: net.ensode.javaee8book.conversationscope.model.Customer@6e1c51b4[firstName=Daniel,middleName=,lastName=Jones,addrLine1=123 Basketball Ct,addrLine2=,addrCity=Montgomery,state=AL,zip=36101,phoneHome=<null>,phoneWork=<null>,phoneMobile=<null>] 

When we submit the third page in our wizard (not shown), additional bean properties corresponding to the fields on that page are populated.

When we are at the point where we don't need to keep the customer information in memory anymore, we need to call the end() method on the Conversation bean that was injected into our code. This is exactly what we do in our code before displaying the confirmation page:

public String navigateToConfirmationPage() { 
        System.out.println(customer); 
        conversation.end(); 
        return "confirmation"; 
    } 

After the request to show the confirmation page is completed, our conversation-scoped bean is destroyed, since we invoked the end() method in our injected Conversation class.

We should note that, since the conversation, scope requires an instance of javax.enterprise.context.Conversation to be injected, this scope requires that the action in the command button or link used to navigate between pages be an expression resolving to a named bean method. Using static navigation won't work, since the Conversation instance won't be injected anywhere.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.136.17.139