3 Contexts and Dependency Injection

In a normal Java application, it is the sole responsibility of the programmer to ensure that classes are instantiated. With CDI, however, the process is somewhat different, since its main component is a so-called “container” that creates instances of classes independently and removes them from memory as needed. The object diagram below shows the relationship between a container and the instances it manages. An object diagram is used in preference to a class diagram, since on this occasion, it is instances – not classes – that we wish to look at.

Object diagram of a container and the instances it manages
Fig. 3-1 Object diagram of a container and the instances it manages

With a small number of exceptions, the CDI container can manage instances of any concrete class and is used particularly to manage JavaBeans and EJB session beans. Classes managed by CDI are generally referenced as beans. A simple annotation is all that is required to ensure that CDI manages these classes as beans[1].

Incidentally, instances of beans do not possess a reference to the container; rather, the container possesses a reference to them. In the literature, this concept is also referred to as Inversion of Control (IoC).

Dealing with a container poses a number of questions, primarily questions regarding when the instances are created and deleted and how these instances are referenced. These and other questions will be answered in the following sections.

3.1 The Scope of a Bean

The point in time at which a bean is created and deleted depends on the scope of the bean. CDI also makes it possible to create our own scopes. However, the only ones of importance for us currently are the RequestScope, the SessionScope, the ViewScope and the DependentScope.

3.1.1 RequestScope

A bean with RequestScope is newly created for every incoming request. If the request is ended, the bean is deleted again (or, strictly speaking, is marked by the container for deletion; the actual deletion is then carried out at a later point by the Garbage Collector).

If multiple requests are received by the server simultaneously, a new bean is created for each. Data stored in the bean is lost when the request ends. Since a request usually has a very short lifespan (shorter than a second), beans with RequestScope are also very short-lived. For this reason, they’re not suited to saving data that’s required for a longer time, such as user data. However, these beans are more economical, since they do not bind to resources long-term.

It goes without saying that the container instantiates a bean with RequestScope only when the bean is referenced in the request; otherwise, resources would be used unnecessarily.

To specify that a bean has RequestScope, we must add the annotation @RequestScoped (from the package javax.enterprise.context) to the bean class.

3.1.2 SessionScope

A bean with SessionScope is created anew for each user session. The bean is only deleted when the user session is ended or when a timeout occurs due to a long period of inactivity.

This means that each user owns their own instance of this bean and thus that beans with SessionScope are ideally suited for storing user data. A good example in our application is the CampaignListProducer, which contains the list of all of the user’s Campaign objects.

Since a user session can last for a very long time (several hours), the server must sometimes cache an inactive user session to save on resources. In light of this, beans with SessionScope must be serializable – that is, they must implement the interface Serializable from the java.io package. The server can serialize such a bean, save it to the hard disk and de-serialize it again as needed. Beans with SessionScope therefore require more resources than beans with RequestScope and as such, beans should only obtain a SessionScope when absolutely necessary.

To specify that a bean has SessionScope, we must add the annotation @SessionScoped (from the package javax.enterprise.context) to the bean class.

3.1.3 ViewScope

One other scope for CDI beans, ViewScope[2], was introduced in Java EE 7 to facilitate better use of resources. This scope is exclusively of interest for applications that use JavaServer Faces[3]. Note, therefore, that although this scope is a CDI scope, it is provided by JSF since Verison 2.2, not CDI.

With this scope, the lifespan of the beans depends on the current view components. If a bean is referenced anew in a JSF view, a new instance of the bean is created. If the view components are deleted, the CDI container in turn removes the beans that were initialised within the view and that have the ViewScope. A JSF view usually exists across the span of multiple requests. For this reason, a bean with ViewScope has a longer lifespan than one with RequestScope.

This is of particular interest for beans that store data to be validated, since they must survive longer than a request. In the case of these beans, however, it would be a waste of resources to save them in the user session via SessionScope.

To specify that a bean has ViewScope, we must add the annotation @ViewScoped (from the javax.faces.view package) to the bean class. The differing package name makes it evident that the scope does not belong to CDI.

3.1.4 DependentScope

This scope simply means that the lifespan of the bean is dependent on another bean and therefore cannot exist independently of this other bean. A bean with DependentScope is created and deleted at the same time as the bean on which it is dependent.

The DependentScope is defined by the annotation @Dependent from the package javax.enterprise.context.

3.1.5 Setting the Scopes for Our Application

After all the theoretic background it is now time for the first code changes on the given sample application. Please click the link below and start the application as explained in Chapter 2:

Start Cloud IDE

Start Cloud IDE

If you check the sample applications code, you see that SessionScope is used for all our beans. This means that our application functions as desired, but that its use of resources is not as good as it could be.

To improve our use of resources, we can take advantage of the structure built up for the sample application:

Data that must survive longer than the lifespan of a JSF view have been stored in the CampaignListProducer and CampaignProducer classes. These data must continue to use SessionScope.

The controller beans – whose actual task is to manage the control flow – will be used, in a few cases, to save data that must be preserved beyond the lifespan of a view. Examples of such data are the Campaign object for deletion in the ListCampaignsController class and the donations that are created in DonateMoneyController.

Since these data must be preserved over multiple requests, the RequestScope is not suitable to be used. The ViewScope, on the other hand, is ideal, since it deals exclusively with data that are required locally in the current view.

This is a conscious design decision: the controller beans are permitted solely to cache data that is local for the view.

Attentive readers will have noticed that not every controller bean would require a ViewScope. The ListDonationsController, for example, could be managed solely using a RequestScope, since it does not store any data.

This said, we must remember that the decision to permit data to be saved is a design one. As such, this condition could potentially be changed for any bean at a later date. We will therefore now set the scope of all controller beans to the ViewScope, including the ListDonationsController. While this admittedly results in less-than-optimal resource use, it does mean that all controller beans are now uniform in terms of their scope.

The authors take the view that this results in a clear design whilst also avoiding potentially confusing future discussions about why one controller bean is ViewScoped and another is RequestScoped.

For your convenience find below a link to our sample application with all the necessary scope changes done:

Start Cloud IDE

Start Cloud IDE (Scopes changed)

3.2 Referencing Beans Via Dependency Injection

So far, we have explained how a container instantiates and deletes a bean. What we’ve yet to discover is how a bean is referenced. This is done using the annotation @Inject from the package javax.inject. Consider the following snippet from the EditCampaignController:

@Inject
private CampaignListProducer campaignListProducer;

This indicates that the attribute campaignListProducer is to store an instance of the bean CampaignListProducer. Without the annotation @Inject, the attribute would have an undefined value. For the container, however, this annotation serves as an indication that an instance of the type (in this case EditCampaignController) should be referenced in the annotated attribute following the instantiation of the bean (in this case EditCampaignController).

Thus, this annotation is used to make the reference of a bean available in another bean. This process is known as dependency injection. The relationships between the classes in our example are shown in the class diagram Fig. 3-2.

Relationships between the container and the beans EditCampaignController and CampaignListProducer
Fig. 3-2 Relationships between the container and the beans EditCampaignController and CampaignListProducer

At this point, we are still unsure as to which instance of CampaignListProducer is taken at runtime. However, this is actually clearly defined, since the bean EditCampaignController is bound to the current JSF view through the ViewScope. This, in turn, is assigned to a specific session – that of the current user. Furthermore, since the CampaignListProducer bean is located in SessionScope, exactly one instance of this bean exists per user session. It is precisely this instance that is referenced in our example.

This said, what if the type of instance variable is a superclass or interface that is implemented by more than one bean? According to what we currently know, the container cannot unambiguously resolve the bean. This problem can be tackled using so-called qualifiers and is looked at in Chapter 4.

Incidentally, the annotation @Inject can be used not only with attributes, but also with constructors or methods. This functionality is not required in our sample application. However, for the sake of completeness, we will show briefly how it would look below.

If the constructor is annotated with @Inject, the other beans can be passed as parameters. In this case, the container passes the other beans at the time the bean is instantiated. In our example, this would look as follows:

private CampaignListProducer campaignListProducer;

@Inject
public EditCampaignController(CampaignListProducer campaignListProducer) {
    this.campaignListProducer = campaignListProducer;
}

It is also possible to annotate methods with @Inject. After the instantiation of the bean, the container invokes these methods and passes the beans that are specified in the method parameters. Here is the code for our example:

private CampaignListProducer campaignListProducer;

@Inject
public void setCampaignListProducer(CampaignListProducer campaignListProducer) {
    this.campaignListProducer = campaignListProducer;
}

3.3 The Lifecycle

As we’ve already mentioned, beans are instantiated and deleted by the container. The programmer can specify methods to be invoked by the container at certain points within a bean’s lifecycle. In the following section, we will introduce the two lifecycle methods used by CDI. These are marked using the annotations @PostConstruct and @PreDestroy.

3.3.1 The PostConstruct Lifecycle Method

If the programmer annotates a method of the bean with the annotation @PostConstruct from the package javax.annotation, this method will be invoked immediately after the instantiation of the bean by the container.

Unlike the bean constructor, all dependencies to other beans are resolved at the time the method with the @PostConstruct annotation is invoked. This means that the attributes annotated with @Inject already contain the references to the beans and the methods annotated with @Inject have already been invoked.

As an example, we will now take the beans DonateMoneyController and CampaignListProducer and replace the constructor with an initialization method init that is annotated with @PostConstruct.

For the DonateMoneyController, this means that

public DonateMoneyController() {
    this.donation = new Donation();
}

is replaced by

@PostConstruct
public void init() {
    this.donation = new Donation();
}

This has the tangible advantage that the method init – unlike the constructor – can be invoked afresh, causing the bean to be reinitialized. This means that in the method doDonation, the line

this.donation = new Donation();

can be replaced by

init();

Following the same logic, we will now replace the constructor for the CampaignListProducer. In this case,

public CampaignListProducer() {
    campaigns = createMockCampaigns();
}

is replaced by

@PostConstruct
public void init() {
    campaigns = createMockCampaigns();
}

At this stage, this does not offer us any extra advantage; in a later stage, however, we might use the method init to reset the CampaignListProducer, to provide the initial data after injecting the bean. By carrying out this step now, we are making preparations for future steps in the development of our application.

Start Cloud IDE

Start Cloud IDE (Lifecycle)

3.3.2 The PreDestroy Lifecycle Method

Methods of a bean annotated with @PreDestroy – from the package javax.annotation – are invoked by the container before the bean is deleted from storage. This enables the developer to free up resources that the bean has created – by deleting temporary files, for example.

Since this functionality is not required in our sample application, we will not make any changes of this nature here.

3.4 Use Any Class as a Bean with the Producer Method

Until now, the only classes we have been able to use as beans are those with either a parameterless constructor or a constructor annotated with @Inject. Thanks to this convention, the container can produce instances of these beans independently. According to what we have learned so far, however, this is not possible for classes with other kinds of constructor.

CDI provides special methods to enable us to use a class of our choosing as a bean. These methods have the annotation @Produces from the package javax.enterprise.inject. Such producer methods create instances of user-selected classes, rendering them available as beans within the container and enabling them to be combined with the annotation @Inject as discussed in section 3.2.

We will now use this functionality in the class Resources, which contains a range of producer methods for making resources available to the application as beans. Listing 3-1 contains the source text of the class, which must be saved in the package press.turngeek.mycampaign.util.

package press.turngeek.mycampaign.util;

import javax.enterprise.context.Dependent;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.faces.context.FacesContext;
import java.util.logging.Logger;

@Dependent
public class Resources {
  
  @Produces
  public Logger produceLog() {
    return Logger.getLogger("MyLogger", "messages");
  }

  @Produces
  @RequestScoped
  public FacesContext produceFacesContext() {
    return FacesContext.getCurrentInstance();
  }

}

Listing 3-1 Resources class

The Resources class provides a logger with the name MyLogger and the current FacesContext. Both resources can be used in other beans by means of the annotation @Inject.

A logger is a utility class that records outputs in a log file. The logger uses the resource bundle messages for the internationalization of the log outputs. This means that messages issued by the logger must be defined in the files messages_en.properties (for English) and messages_de.properties (for German). We’ll talk more about this in just a moment.

The bean DonateMoneyController makes direct use of the logger and the FacesContext. Therefore, we will begin by injecting these into the bean as attributes:

@Inject
private FacesContext facesContext;

@Inject
private Logger logger;

These resources can then be used in the method doDonation. First, the line

final FacesContext facesContext = FacesContext.getCurrentInstance();

must be deleted, which will cause the injected instance variable facesContext to be referenced in the method instead.

At this point, it also makes sense to issue a log message about the successful donation. This is where the logger comes into play. Through the changes we have made, the method doDonation now appears as follows:

public String doDonation() {
    logger.log(Level.INFO, "log.donateMoney.thank_you", new Object[]{getDonation().getDonorName(), getDonation().getAmount()});
    final ResourceBundle resourceBundle = facesContext.getApplication().getResourceBundle(facesContext, "msg");
    final String msg = resourceBundle.getString("donateMoney.thank_you");
    facesContext.addMessage(
        null,
        new FacesMessage(FacesMessage.SEVERITY_INFO, msg, null));
    init();
    return Pages.DONATE_MONEY;
}

The log message to be issued is selected by the key log.donateMoney.thank_you belonging to the resource bundle messages. We must now modify the resource bundle with the output text in our two target languages, English and German.

For English, insert the following line at the end of the file messages_en.properties:

log.donateMoney.thank_you={0} has donated {1} Euro.

For German, add the equivalent line to the file messages_de.properties:

log.donateMoney.thank_you={0} hat {1} Euro gespendet.

One drawback is the naming of the logger as MyLogger, which goes against the usual convention of naming the logger after the class that accesses it.

In order to assign the logger the name of its accessing class, we can share runtime information about the associated bean class with the producer method. To do this, the method produceLog from the class Resources is passed a parameter of the type InjectionPoint from the package javax.enterprise.inject.spi.

@Produces
public Logger produceLog(InjectionPoint injectionPoint) {
    return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName(), "messages");
}

The expression injectionPoint.getMember().getDeclaringClass() returns the Class object of the accessing class, which integrates the logger using the annotation @Inject. If the logger is now used in the bean DonateMoneyController, it will have the name DonateMoneyController – or in general terms, the name of the accessing bean.

Since instances created by the producer methods are CDI beans, these also have a scope. By default, this will be scope of producer method’s class, so in our case it is the DependentScope (see section 3.1.4). This can be changed if so desired by annotating the producer method with the desired scope.

In our case, the logger stays on DependentScope in order to ensure that a fresh instance of the logger is created for each accessing bean. However, the producer method for the FacesContext will be set to RequestScope, since this object does not change within a request.

Furthermore, Java EE internally provides a producer method for the HttpServletRequest. We will use this now by replacing the method getAppUrl in the EditDonationFormController with the following snippet of code:

@Inject
private HttpServletRequest req;

private String getAppUrl() {
    String scheme = req.getScheme();
    String serverName = req.getServerName();
    int serverPort = req.getServerPort();
    String contextPath = req.getContextPath();
    return scheme+"://"+serverName+":"+serverPort+contextPath;
}

As a result of this change, the current request’s HttpServletRequest will be injected in the controller and used directly in the method getAppUrl. Previously, it was necessary to retrieve this via the FacesContext every time the method was accessed.

3.5 Producing domain objects

So far we have used producer methods for creating technically related objects like Logger and HttpServletRequest. In this section we will see they are also very helpful for providing domain related data objects. There are two domain related components in our application that could benefit from producer methods, namely the beans CampaignProducer and CampaignListProducer.

The task of the CampaignListProducer is to provide a list of Campaign objects. A class wishing to use this list does not actually require a dependency to the CampaignListProducer, but rather solely to this list. To make this possible, we must annotate the getCampaigns method of the CampaignListProducer with @Produces. Since no other bean in the application provides a list of Campaign objects, this list can now be injected in other beans as shown below:

@Inject
private List<Campaign> campaigns;

This being said, we actually want to refrain from making any changes of this nature, since the following section will introduce another method for avoiding dependencies to the CampaignListProducer: application-wide messages.

Nonetheless, we still want to use the new producer method getCampaigns so that we can reference it in Facelets. To do this, we will additionally add the @Named annotation to this method and remove the same annotation at the class level.

This enables the JSF DataTable component of the file listCampaigns.xhtml to access the list of Campaign objects directly using the name campaigns and removes the need for it to detour via the CampaignListProducer. To implement this change, modify the following lines of the file listCampaigns.xhtml:

<p:dataTable value="#{campaignListProducer.campaigns}" var="campaign">

to the following expression:

<p:dataTable value="#{campaigns}" var="campaign">

As a result of this, the class CampaignListProducer will now contain a producer method that provides a list of Campaign objects and thus does what it says on the tin! You see now that the naming with the suffix Producer wasn’t a coincidence.

Following the same principle, we now want to introduce similar producer methods for the bean CampaignProducer. To do this, we will remove the @Named bean annotation at the class level and add the annotations @Named and @Produces to the getter methods getSelectedCampaign and isAddMode.

For the latter, this results in the following definitions:

@Produces
@Named
public Campaign getSelectedCampaign() {
    return campaign;
}

and

@Produces
@Named
public boolean isAddMode() {
    return mode == Mode.ADD;
}

Following this change, we can use the producer methods directly in the Facelets. To do this, we must replace all references to the getter in the files editCampaign.xhtml and listDonations.xhtml. As we do this, we need only to take the EL expressions – that is, everything inside #{ and } – into account.

In specific terms, this means that we must access the Facelets and replace the expressions campaignProducer.selectedCampaign and campaignProducer.addMode with selectedCampaign and addMode respectively. Since we are dealing with a few different references, our best option is to use the Search and Replace function in our editor. Lastly, it’s important to be careful while we work and to test any changes in order to avoid problems at a later stage. Worst case we have you covered with the following Cloud IDE link:

Start Cloud IDE

Start Cloud IDE (End Contexts & DI)

Discussion

Use the message board below to give the authors your feedback or to discuss this page’s topic with other readers (in English please!). Please don’t expect the authors to answer directly, but they might update the content of this site according to your feedback.


  1. Before CDI 1.1, it was necessary for an additional empty file called WEB-INFbeans.xml to be contained in the application archive in order for activation to occur.
  2. The ViewScope actually existed in JSF before version 2.2; however, it could only be used for JSF managed beans, not for CDI beans.
  3. SessionScope and RequestScope, in contrast, do not require JSF – they function with any application that is built solely on servlets.