ensures proper creation and lifecycle management. In the real world, you would rarely
inject POJOs into a servlet; you would probably use a UI framework (such as JSF 2) or
expose your service via representational
state transfer (REST). In such cases, the use
of CDI is even more beneficial.
To illustrate, consider a simple
MessageMe application that stores a
message string in a database. The JSF 2
markup consists of two components:
input Text and commandButton. As shown
in Listing 2, input Text is value-bound to a
class with the name index with a property
message, which has, in turn, a content attribute. commandButtons’s action attribute
is bound to the save method of the backing
bean with the name index.
Listing 3 shows the backing bean implemented as a request-scoped CDI bean,
using the @RequestScoped annotation for
request handling. A JSF 2 managed bean
(using the @ManagedBean annotation)
could also work, but CDI is just as powerful.
And using CDI everywhere simplifies the
architecture, with a single glue API across
all application layers.
The annotation @Named (as specified
in the JSR 330 specification and implemented in Guice and Spring) makes the
index backing bean visible in all expression
language (EL) markup. It works according to
the “convention over configuration” principle: the name of the backing bean in JSF
2 is derived from the class name. The first
letter is not capitalized.
The Message class is implemented as a
JPA 2 entity, as shown in Listing 4.
The next class in this example is the
Messaging class, which is implemented
as an EJB 3. 1 session bean. This class represents a pragmatic exception to the “CDI
everywhere” rule. EJBs provide many capabilities, such as transactions, pooling, Java
Management Extensions (JMX) monitoring,
and asynchronous execution—all for the
price of a single additional @Stateless
annotation. In future Java EE releases,
these aspects are likely to be extracted from
EJBs and made available in CDI as well. In
Java EE 6, however, a boundary or facade of
a business component is most effectively
implemented as a stateless session bean.
The @Asynchronous annotation in
Listing 5 is particularly interesting. It
enables the asynchronous but transactional
execution of methods and is available only
for EJBs. Note that the Messaging EJB is
injected with @Inject and not @EJB. In
practice, either annotation would work, with
virtually no difference. The use of @Inject is
slightly more powerful and supports inheritance. The @EJB annotation, on the other
hand, works only with EJBs.
The MessageStore class in Listing 6 is a
Data Access Object (DAO) that encapsulates
access to the EntityManager.
ECB: A PRAGMATIC SEPARATION
OF CONCERNS
If you review the packaging of the application
described above, you will notice separate
boundary, control, and entity packages. This
packaging approach is an implementation of
the Entity Control Boundary (ECB) pattern.
The boundary layer is the facade, the control
layer is responsible for the implementation of
process- and entity-independent logic, and
the entity layer contains rich domain objects.
With Java EE 6 and especially the availability of JPA 2, CDI, and EJB, the implementation of all three layers can lead to empty
Code Listing 3: A CDI backing bean with injected EJB
package com.abien.messageme.presentation;
import com.abien. messageme.business.messaging.boundary.Messaging;
import com.abien.messageme.business.messaging.entity.Message;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
@Named
@RequestScoped
public class Index {
@Inject
Messaging ms;
private Message message = new Message();
public Message getMessage() {
return message;
}
public void save(){
ms.store(message);
}
}
Code Listing 4: JPA 2 entity validated with Bean Validation
package com.abien.messageme.business.messaging.entity;
@Entity
public class Message {
@Id
@GeneratedValue
private Long id;
@Size(min= 2,max=140)
private String content;
public Message(String content) {
this.content = content;
}
public Message() { /*required by JPA */}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Long getId() {
return id;
}
}