SeamFramework.orgCommunity Documentation

Chapter 2. More about beans

2.1. The anatomy of a bean
2.1.1. Bean types, qualifiers and dependency injection
2.1.2. Scope
2.1.3. EL name
2.1.4. Alternatives
2.1.5. Interceptor binding types
2.2. What kinds of classes are beans?
2.2.1. Managed beans
2.2.2. Session beans
2.2.3. Producer methods
2.2.4. Producer fields

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:

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:

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 {
   ...
}

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.

Note

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 { ... }

Note

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.

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:

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.

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.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 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.