SeamFramework.orgCommunity Documentation
A bean is usually an application class that contains business logic. It may be called directly from Java code, or it may be invoked via the Unified EL. A bean may access transactional resources. Dependencies between beans are managed automatically by the container. Most beans are stateful and contextual. The lifecycle of a bean is always managed by the container.
Let's back up a second. What does it really mean to be contextual? Since beans may be stateful, it matters which bean instance I have. Unlike a stateless component model (for example, stateless session beans) or a singleton component model (such as servlets, or singleton beans), different clients of a bean see the bean in different states. The client-visible state depends upon which instance of the bean the client has a reference to.
However, like a stateless or singleton model, but unlike stateful session beans, the client does not control the lifecycle of the instance by explicitly creating and destroying it. Instead, the scope of the bean determines:
the lifecycle of each instance of the bean and
which clients share a reference to a particular instance of the bean.
For a given thread in a CDI application, there may be an active context associated with the scope of the bean. This context may be unique to the thread (for example, if the bean is request scoped), or it may be shared with certain other threads (for example, if the bean is session scoped) or even all other threads (if it is application scoped).
Clients (for example, other beans) executing in the same context will see the same instance of the bean. But clients in a different context may see a different instance (depending on the relationship between the contexts).
One great advantage of the contextual model is that it allows stateful beans to be treated like services! The client need not concern itself with managing the lifecycle of the bean it's using, nor does it even need to know what that lifecycle is. Beans interact by passing messages, and the bean implementations define the lifecycle of their own state. The beans are loosely coupled because:
they interact via well-defined public APIs
their lifecycles are completely decoupled
We can replace one bean with another different bean that implements the same interface and has a different lifecycle (a different scope) without affecting the other bean implementation. In fact, CDI defines a simple facility for overriding bean implementations at deployment time, as we will see in Section 4.7, “Alternatives”.
Note that not all clients of a bean are beans themselves. Other objects such as servlets or message-driven beans—which are by nature not injectable, contextual objects—may also obtain references to beans by injection.
Enough hand-waving. More formally, the anatomy of a bean, according to the spec:
A bean comprises the following attributes:
A (nonempty) set of bean types
A (nonempty) set of qualifiers
A scope
Optionally, a bean EL name
A set of interceptor bindings
A bean implementation
Furthermore, a bean may or may not be an alternative.
Let's see what all this new terminology means.
Beans usually acquire references to other beans via dependency injection. Any injected attribute specifies a "contract" that must be satisfied by the bean to be injected. The contract is:
a bean type, together with
a set of qualifiers.
A bean type is a user-defined class or interface; a type that is client-visible. If the bean is an EJB
session bean, the bean type is the @Local
interface or bean-class local view. A bean
may have multiple bean types. For example, the following bean has four bean types:
public class BookShop
extends Business
implements Shop<Book> {
...
}
The bean types are BookShop
, Business
and
Shop<Book>
, as well as the implicit type java.lang.Object
.
(Notice that a parameterized type is a legal bean type).
Meanwhile, this session bean has only the local interfaces BookShop
,
Auditable
and java.lang.Object
as bean types, since the bean class,
BookShopBean
is not a client-visible type.
@Stateful
public class BookShopBean
extends Business
implements BookShop, Auditable {
...
}
The bean types of a session bean include local interfaces and the bean class local view (if any). EJB remote interfaces are not considered bean types of a session bean. You can't inject an EJB using its remote interface unless you define a resource, which we'll meet in Chapter 14, Java EE component environment resources.
Bean types may be restricted to an explicit set by annotating the bean with the @Typed
annotation and listing the classes that should be bean types. For instance, the bean types of this bean have
been restricted to Shop<Book>
, together with java.lang.Object
:
@Typed(Shop.class)
public class BookShop
extends Business
implements Shop<Book> {
...
}
Sometimes, a bean type alone does not provide enough information for the container to know which bean to inject.
For instance, suppose we have two implementations of the PaymentProcessor
interface:
CreditCardPaymentProcessor
and DebitPaymentProcessor
. Injecting a field of
type PaymentProcessor
introduces an ambiguous condition. In these cases, the client must
specify some additional quality of the implementation it is interested in. We model this kind of "quality" using
a qualifier.
A qualifier is a user-defined annotation that is itself annotated @Qualifer
. A qualifier
annotation is an extension of the type system. It lets us disambiguate a type without having to fall back to
string-based names. Here's an example of a qualifier annotation:
@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface CreditCard {}
You may not be used to seeing the definition of an annotation. In fact, this might be the first time you've encountered one. With CDI, annotation definitions will become a familiar artifact as you'll be creating them from time to time.
Pay attention to the names of the built-in annotations in CDI and EJB. You'll notice that they are often adjectives. We encourage you to follow this convention when creating your custom annotations, since they serve to describe the behaviors and roles of the class.
Now that we have defined a qualifier annotation, we can use it to disambiguate an injection point. The
following injection point has the bean type PaymentProcessor
and qualifier
@CreditCard
:
@Inject @CreditCard PaymentProcessor paymentProcessor
For each injection point, the container searches for a bean which satisfies the contract, one which has the bean type and all the qualifiers. If it finds exactly one matching bean, it injects an instance of that bean. If it doesn't, it reports an error to the user.
How do we specify that qualifiers of a bean? By annotating the bean class, of course! The following bean
has the qualifier @CreditCard
and implements the bean type PaymentProcessor
.
Therefore, it satisfies our qualified injection point:
@CreditCard
public class CreditCardPaymentProcessor
implements PaymentProcessor { ... }
If a bean or an injection point does not explicitly specify a qualifier, it has the default qualifier, @Default
.
That's not quite the end of the story. CDI also defines a simple resolution rule that helps the container decide what to do if there is more than one bean that satisfies a particular contract. We'll get into the details in Chapter 4, Dependency injection and programmatic lookup.
The scope of a bean defines the lifecycle and visibility of its instances. The CDI context model is extensible, accommodating arbitrary scopes. However, certain important scopes are built into the specification, and provided by the container. Each scope is represented by an annotation type.
For example, any web application may have session scoped bean:
public @SessionScoped
class ShoppingCart implements Serializable { ... }
An instance of a session-scoped bean is bound to a user session and is shared by all requests that execute in the context of that session.
Keep in mind that once a bean is bound to a context, it remains in that context until the context is destroyed. There is no way to manually remove a bean from a context. If you don't want the bean to sit in the session indefinitely, consider using another scope with a shorted lifespan, such as the request or conversation scope.
If a scope is not explicitly specified, then the bean belongs to a special scope called the dependent pseudo-scope. Beans with this scope live to serve the object into which they were injected, which means their lifecycle is bound to the lifecycle of that object.
We'll talk more about scopes in Chapter 5, Scopes and contexts.
If you want to reference a bean in non-Java code that supports Unified EL expressions, for example, in a JSP or JSF page, you must assign the bean an EL name.
The EL name is specified using the @Named
annotation, as shown here:
public @SessionScoped @Named("cart")
class ShoppingCart implements Serializable { ... }
Now we can easily use the bean in any JSF or JSP page:
<h:dataTable value="#{cart.lineItems}" var="item">
...
</h:dataTable>
The @Named
annotation is not what makes the class a bean. Most classes in a bean
archive are already recognized as beans. The @Named
annotation just makes it
possible to reference the bean from the EL, most commonly from a JSF view.
We can let CDI choose a name for us by leaving off the value of the @Named
annotation:
public @SessionScoped @Named
class ShoppingCart implements Serializable { ... }
The name defaults to the unqualified class name, decapitalized; in this case,
shoppingCart
.
We've already seen how qualifiers let us choose between multiple implementations of an interface
at development time. But sometimes we have an interface (or other bean type) whose implementation
varies depending upon the deployment environment. For example, we may want to use a mock
implementation in a testing environment. An alternative may be declared by
annotating the bean class with the @Alternative
annotation.
public @Alternative
class MockPaymentProcessor extends PaymentProcessorImpl { ... }
We normally annotate a bean @Alternative
only when there is some other
implementation of an interface it implements (or of any of its bean types). We can choose between
alternatives at deployment time by selecting an alternative in the CDI
deployment descriptor META-INF/beans.xml
of the jar or Java EE module that uses
it. Different modules can specify that they use different alternatives.
We cover alternatives in more detail in Section 4.7, “Alternatives”.
You might be familiar with the use of interceptors in EJB 3.0. In Java EE 6, this functionality has been generalized to work with other managed beans. That's right, you no longer have to make your bean an EJB just to intercept its methods. Holler. So what does CDI have to offer above and beyond that? Well, quite a lot actually. Let's cover some background.
The way that interceptors were defined in Java EE 5 was counter-intuitive. You were required to specify the
implementation of the interceptor directly on the implementation
of the EJB, either in the @Interceptors
annotation or in the XML descriptor. You might as
well just put the interceptor code in the implementation! Second, the order in which
the interceptors are applied is taken from the order in which they are declared in the annotation or the XML
descriptor. Perhaps this isn't so bad if you're applying the interceptors to a single bean. But, if you are
applying them repeatedly, then there's a good chance that you'll inadvertently define a different order for
different beans. Now that's a problem.
CDI provides a new approach to binding interceptors to beans that introduces a level of indirection (and thus control). We must define an interceptor binding type to describe the behavior implemented by the interceptor.
An interceptor binding type is a user-defined annotation that is itself annotated @InterceptorBinding
.
It lets us bind interceptor classes to bean classes with no direct dependency between the two classes.
@InterceptorBinding
@Inherited
@Target( { TYPE, METHOD })
@Retention(RUNTIME)
public @interface Transactional {}
The interceptor that implements transaction management declares this annotation:
public @Transactional @Interceptor
class TransactionInterceptor { ... }
We can apply the interceptor to a bean by annotating the bean class with the same interceptor binding type:
public @SessionScoped @Transactional
class ShoppingCart implements Serializable { ... }
Notice that ShoppingCart
and TransactionInterceptor
don't know
anything about each other.
Interceptors are deployment-specific. (We don't need a TransactionInterceptor
in our
unit tests!) By default, an interceptor is disabled. We can enable an interceptor using the CDI deployment
descriptor META-INF/beans.xml
of the jar or Java EE module. This is also where we
specify the interceptor ordering.
We'll discuss interceptors, and their cousins, decorators, in Chapter 9, Interceptors and Chapter 10, Decorators.
We've already seen two types of beans: JavaBeans and EJB session beans. Is that the whole story? Actually, it's just the beginning. Let's explore the various kinds of beans that CDI implementations must support out-of-the-box.
A managed bean is a Java class. The basic lifecycle and semantics of a managed bean are defined by the
Managed Beans specification. You can explicitly declare a managed bean by annotating the bean class
@ManagedBean
, but in CDI you don't need to. According to the specification, the CDI
container treats any class that satisfies the following conditions as a managed bean:
It is not a non-static inner class.
It is a concrete class, or is annotated @Decorator
.
It is not annotated with an EJB component-defining annotation or declared as an EJB bean class in
ejb-jar.xml
.
It does not implement javax.enterprise.inject.spi.Extension
.
It has an appropriate constructor—either:
the class has a constructor with no parameters, or
the class declares a constructor annotated @Inject
.
According to this definition, JPA entities are technically managed beans. However, entities have their own
special lifecycle, state and identity model and are usually instantiated by JPA or using new
.
Therefore we don't recommend directly injecting an entity class. We especially recommend against assigning
a scope other than @Dependent
to an entity class, since JPA is not able to persist
injected CDI proxies.
The unrestricted set of bean types for a managed bean contains the bean class, every superclass and all interfaces it implements directly or indirectly.
If a managed bean has a public field, it must have the default scope @Dependent
.
Managed beans support the @PostConstruct
and @PreDestroy
lifecycle
callbacks.
Session beans are also, technically, managed beans. However, since they have their own special lifecycle and take advantage of additional enterprise services, the CDI specification considers them to be a different kind of bean.
Session beans belong to the EJB specification. They have a special lifecycle, state management and concurrency model that is different to other managed beans and non-managed Java objects. But session beans participate in CDI just like any other bean. You can inject one session bean into another session bean, a managed bean into a session bean, a session bean into a managed bean, have a managed bean observe an event raised by a session bean, and so on.
Message-driven and entity beans are by nature non-contextual objects and may not be injected into other objects. However, message-driven beans can take advantage of some CDI functionality, such as dependency injection, interceptors and decorators. In fact, CDI will perform injection into any session or message-driven bean, even those which are not contextual instances.
The unrestricted set of bean types for a session bean contains all local interfaces of the bean and their
superinterfaces. If the session bean has a bean class local view, the unrestricted set of bean types
contains the bean class and all superclasses. In addition, java.lang.Object
is a bean
type of every session bean. But remote interfaces are not included in the set of bean
types.
There's no reason to explicitly declare the scope of a stateless session bean or singleton session bean.
The EJB container controls the lifecycle of these beans, according to the semantics of the @Stateless
or @Singleton
declaration. On the other hand, a stateful session bean may have any scope.
Stateful session beans may define a remove method, annotated @Remove
,
that is used by the application to indicate that an instance should be destroyed. However, for a contextual
instance of the bean—an instance under the control of CDI—this method may only be called by the
application if the bean has scope @Dependent
. For beans with other scopes, the application
must let the container destroy the bean.
So, when should we use a session bean instead of a plain managed bean? Whenever we need the advanced enterprise services offered by EJB, such as:
method-level transaction management and security,
concurrency management,
instance-level passivation for stateful session beans and instance-pooling for stateless session beans,
remote or web service invocation, or
timers and asynchronous methods,
When we don't need any of these things, an ordinary managed bean will serve just fine.
Many beans (including any @SessionScoped
or @ApplicationScoped
beans) are available for concurrent access. Therefore, the concurrency management provided by EJB 3.1
is especially useful. Most session and application scoped beans should be EJBs.
Beans which hold references to heavy-weight resources, or hold a lot of internal state benefit from the advanced container-managed lifecycle defined by the EJB stateless/stateful/singleton model, with its support for passivation and instance pooling.
Finally, it's usually obvious when method-level transaction management, method-level security, timers, remote methods or asynchronous methods are needed.
The point we're trying to make is: use a session bean when you need the services it provides, not just
because you want to use dependency injection, lifecycle management, or interceptors. Java EE 6 provides
a graduated programming model. It's usually easy to start with an ordinary managed bean, and later turn
it into an EJB just by adding one of the following annotations: @Stateless
,
@Stateful
or @Singleton
.
On the other hand, don't be scared to use session beans just because you've heard your friends say they're "heavyweight". It's nothing more than superstition to think that something is "heavier" just because it's hosted natively within the Java EE container, instead of by a proprietary bean container or dependency injection framework that runs as an additional layer of obfuscation. And as a general principle, you should be skeptical of folks who use vaguely defined terminology like "heavyweight".
Not everything that needs to be injected can be boiled down to a bean class instantiated by the container
using new
. There are plenty of cases where we need additional control. What if we need
to decide at runtime which implementation of a type to instantiate and inject? What if we need to inject
an object that is obtained by querying a service or transactional resource, for example by executing a JPA
query?
A producer method is a method that acts as a source of bean instances. The method declaration itself describes the bean and the container invokes the method to obtain an instance of the bean when no instance exists in the specified context. A producer method lets the application take full control of the bean instantiation process.
A producer method is declared by annotating a method of a bean class with the @Produces
annotation.
@ApplicationScoped
public class RandomNumberGenerator {
private Random random = new Random(System.currentTimeMillis());
@Produces @Named @Random int getRandomNumber() {
return random.nextInt(100);
}
}
We can't write a bean class that is itself a random number. But we can certainly write a method that returns
a random number. By making the method a producer method, we allow the return value of the method—in this
case an Integer
—to be injected. We can even specify a qualifier—in this case
@Random
, a scope—which in this case defaults to @Dependent
,
and an EL name—which in this case defaults to randomNumber
according to the JavaBeans
property name convention. Now we can get a random number anywhere:
@Inject @Random int randomNumber;
Even in a Unified EL expression:
<p>Your raffle number is #{randomNumber}.</p>
A producer method must be a non-abstract method of a managed bean class or session bean class. A producer method may be either static or non-static. If the bean is a session bean, the producer method must be either a business method of the EJB or a static method of the bean class.
The bean types of a producer method depend upon the method return type:
If the return type is an interface, the unrestricted set of bean types contains the return type, all
interfaces it extends directly or indirectly and java.lang.Object
.
If a return type is primitive or is a Java array type, the unrestricted set of bean types contains
exactly two types: the method return type and java.lang.Object
.
If the return type is a class, the unrestricted set of bean types contains the return type, every superclass and all interfaces it implements directly or indirectly.
Producer methods and fields may have a primitive bean type. For the purpose of resolving dependencies,
primitive types are considered to be identical to their corresponding wrapper types in
java.lang
.
If the producer method has method parameters, the container will look for a bean that satisfies the type and qualifiers of each parameter and pass it to the method automatically—another form of dependency injection.
@Produces Set<Roles> getRoles(User user) {
return user.getRoles();
}
We'll talk much more about producer methods in Chapter 8, Producer methods.
A producer field is a simpler alternative to a producer method. A producer field is
declared by annotating a field of a bean class with the @Produces
annotation—the
same annotation used for producer methods.
public class Shop {
@Produces PaymentProcessor paymentProcessor = ....;
@Produces @Catalog List<Product> products = ....;
}
The rules for determining the bean types of a producer field parallel the rules for producer methods.
A producer field is really just a shortcut that lets us avoid writing a useless getter method. However, in addition to convenience, producer fields serve a specific purpose as an adaptor for Java EE component environment injection, but to learn more about that, you'll have to wait until Chapter 14, Java EE component environment resources. Because we can't wait to get to work on some examples.