Weld SiteCommunity 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 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:
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:
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 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
@Qualifier
. 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. Since 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:
@Decorator
.ejb-jar.xml
.javax.enterprise.inject.spi.Extension
.It has an appropriate constructor—either:
@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:
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.2 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 7 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.
import javax.enterprise.inject.Produces;
@ApplicationScoped
public class RandomNumberGenerator {
private java.util.Random random = new java.util.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:
java.lang.Object
.java.lang.Object
.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.
import javax.enterprise.inject.Produces;
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.