Stateless session beans (EJB 3)

As noted earlier, stateless session beans model tasks don’t maintain conversational state. This means that session beans model tasks can be completed in a single method call, such as placing a bid. However, this does not mean that all stateless session beans contain a single method, as is the case for the PlaceBid-Bean in topic 2. In fact, real-world stateless session beans often contain several closely related business methods, like the BidManager bean we’ll introduce soon. By and large, stateless session beans are the most popular kind of session beans. They are also the most performance efficient. To understand why, take a look at figure 3.3, which shows a high-level schematic of how stateless session beans are typically used by clients.

As you’ll learn in section 3.2.4, stateless beans are pooled. This means that for each managed bean, the container keeps a certain number of instances handy in a pool. For each client request, an instance from the pool is quickly assigned to the client. When the client request finishes, the instance is returned to the pool for reuse. This means that a small number of bean instances can service a relatively large number of clients.

In this section you’ll learn more about developing stateless session beans. We’ll develop part of the business logic of our ActionBazaar system using a stateless session to illustrate its use. You’ll learn how to use ©Stateless annotations as well as various types of business interfaces and lifecycle callbacks supported with stateless session beans.


Stateless session bean instances can be pooled and may be shared between clients. When a client invokes a method in a stateless session bean, the container either creates a new instance in the bean pool for the client or assigns one from the bean pool. The instance is returned to the pool after use.

Figure 3.3 Stateless session bean instances can be pooled and may be shared between clients. When a client invokes a method in a stateless session bean, the container either creates a new instance in the bean pool for the client or assigns one from the bean pool. The instance is returned to the pool after use.

Before we jump into analyzing code, let’s briefly discuss the ActionBazaar business logic that we’ll implement as a stateless session bean.

The BidManagerBean example

Bidding is a critical part of the ActionBazaar functionality. Users can bid on an item and view the current bids, while ActionBazaar administrators and customer service representatives can remove bids under certain circumstances. Figure 3.4 depicts these bid-related actions.

Because all of these bid-related functions are simple, single-step processes, a stateless session bean can be used to model all of them. The BidManagerBean presented in listing 3.1 contains methods for adding, viewing, and canceling (or removing) bids. This is essentially an enhanced, more realistic version of the basic PlaceBid EJB we saw earlier.

Some ActionBazaar bid-related actions. While bidders can place bids and view the current bids on an item, admins can remove bids when needed. All of these actions can be modeled with a singe stateless session bean.

Figure 3.4 Some ActionBazaar bid-related actions. While bidders can place bids and view the current bids on an item, admins can remove bids when needed. All of these actions can be modeled with a singe stateless session bean.

NOTE We are using JDBC for simplicity only because we have not introduced the EJB 3 Java Persistence API (JPA) in any detail quite yet, and we don’t assume you already understand ORM. Using JDBC also happens to demonstrate the usage of dependency injection of resources and the stateless bean lifecycle callbacks pretty nicely! In general, you should avoid using JDBC in favor of JPA once you are comfortable with it.

Listing 3.1 Stateless session bean example

Listing 3.1 Stateless session bean exampleListing 3.1 Stateless session bean example

As you’ve seen before, the ©Stateless annotation marks the POJO as a stateless session bean Q. The BidManagerBean class implements the BidManager interface, which is marked ©Remote ©. We use the ©Resource annotation to perform injection of a JDBC data source Q. The BidManagerBean has a no-argument constructor that the container will use to create instances of BidManagerBid EJB object. The PostConstruct D and PreDestroy Q callbacks are used to manage a JDBC database connection derived from the injected data source. Finally, the addBid business method adds a bid into the database.

We’ll start exploring the features of EJB 3 stateless session beans by analyzing this code next, starting with the ©Stateless annotation.

Using the @Stateless annotation

The ©Stateless annotation marks the BidManagerBean POJO as a stateless session bean. Believe it or not, other than marking a POJO for the purposes of making the container aware of its purpose, the annotation does not do much else. The specification of the ©Stateless annotation is as follows:

tmp2469_thumbtmp2470_thumb

The single parameter, name, specifies the name of the bean. Some containers use this parameter to bind the EJB to the global JNDI tree. Recall that JNDI is essentially the application server’s managed resource registry. All EJBs automatically get bound to JNDI as soon as they catch the container’s watchful eye. You’ll see the name parameter in use again in topic 11 when we discuss deployment descriptors. In listing 3.1, the bean name is specified as BidManager. As the annotation definition shows, the name parameter is optional since it is defaulted to an empty String. We could easily omit it as follows:

tmp2471_thumb

If the name parameter is omitted, the container assigns the name of the class to the bean. In this case, the container assumes the bean name is BidManagerBean. mappedName is a vendor-specific name that you can assign to your EJB; some containers, such as the GlassFish application server, use this name to assign the global JNDI name for the EJB. As we noted, the BidManagerBean implements a business interface named BidManager. Although we’ve touched on the idea of a business interface, we haven’t dug very deeply into the concept. This is a great time to do exactly that.

Specifying bean business interfaces

In section 3.1, we introduced you to EJB interfaces. Now let’s explore a bit more how they work with stateless session beans. Client applications can invoke a stateless session bean in three different ways. In addition to local invocation within the same JVM and remote invocation through RMI, stateless beans can be invoked remotely as web services.

Three types of business interfaces correspond to the different access types; each is identified through a distinct annotation. Let’s take a detailed look at these annotations.

Local interface

A local interface is designed for clients of stateless session beans collocated in the same container (JVM) instance. You designate an interface as a local business interface by using the @Local annotation. The following could be a local interface for the BidManagerBean class in listing 3.1:

tmp2472_thumb

Local interfaces don’t require any special measures in terms of either defining or implementing them.

Remote interface

Clients residing outside the EJB container’s JVM instance must use some kind of remote interface. If the client is also written in Java, the most logical and resource-efficient choice for remote EJB access is Java Remote Method Invocation (RMI). In case you are unfamiliar with RMI. For now, all you need to know is that it is a highly efficient, TCP/IP-based remote communication API that automates most of the work needed for calling a method on a Java object across a network. EJB 3 enables a stateless bean to be made accessible via RMI through the ©Remote annotation. The Bid-Manager business interface in our example uses the annotation to make the bean remotely accessible:

tmp2473_thumb

A remote business interface may extend java.rmi.Remote as we’ve done here, although this is optional. Typically the container will perform byte-code enhancements during deployment to extend java.rmi.Remote if your bean interface does not extend it. Remote business interface methods are not required to throw java.rmi.RemoteException unless the business interface extends the java.rmi. Remote interface. Remote business interfaces do have one special requirement: all parameters and return types of interface methods must be Serializable. This is because only Serializable objects can be sent across the network using RMI.

Web service endpoint interface

The third type of interface is specific to stateless session beans that you haven’t seen yet: the web service endpoint interface (also known as SEI). The ability to expose a stateless session bean as a SOAP-based web service is one of the most powerful features of EJB 3. All you need to do to make a bean SOAP accessible is mark a business interface with the ©javax.jws.WebService annotation. The following defines a simple web service endpoint interface for the BidManagerBean:

tmp2474_thumb

Note we have omitted the cancelBid bean method from the interface; we don’t want this functionality to be accessible via a web service, although it is accessible locally as well as remotely through RMI. The ©WebService annotation doesn’t place any special restrictions on either the interface or the implementing bean. We discuss EJB web services in greater detail in topic 15.

Working with multiple business interfaces

Although it is tempting, you cannot mark the same interface with more than one access type annotation. For example, you cannot mark the BidManager interface in listing 3.1 with both the ©Local and ©Remote annotations instead of creating separate BidManagerLocal (local) and BidManager (remote) interfaces, although both interfaces expose the exact same bean methods.

However, a business interface can extend another interface, and you can remove code duplication by creating a business interface that has common methods and business interfaces that extend the common "parent" interface. For example, you can create a set of interfaces utilizing OO inheritance as follows:

tmp2475_thumb

If you want, you can apply the ©Local, ©Remote, or ©WebService annotation in the bean class without having to implement the business interface as follows:

tmp2476_thumb

The preceding code marks the BidManager interface as remote through the bean class itself. This way, if you change your mind later, all you’d have to do is change the access type specification in the bean class without ever touching the interface. Next, we move on to discussing the EJB lifecycle in our example.

Using bean lifecycle callbacks

We introduced you to lifecycle callback methods, or callbacks, earlier in the topicc; now let’s take a deeper look at how they are used with stateless session beans. As far as EJB lifecycles go, stateless session beans have a simple one, as depicted in figure 3.5. In effect, the container does the following:

The chicken or the egg—the stateless session bean lifecycle has three states: does not exist, idle, or busy. As a result, there are only two lifecycle callbacks corresponding to bean creation and destruction.

Figure 3.5 The chicken or the egg—the stateless session bean lifecycle has three states: does not exist, idle, or busy. As a result, there are only two lifecycle callbacks corresponding to bean creation and destruction.

1 Creates bean instances using the default constructor as needed.

2 Injects resources such as database connections.

3 Puts instances in a managed pool.

4 Pulls an idle bean out of the pool when an invocation request is received from the client (the container may have to increase the pool size at this point).

5 Executes the requested business method invoked through the business interface by the client.

6 When the business method finishes executing, pushes the bean back into the "method-ready" pool.

7 As needed, retires (a.k.a. destroys) beans from the pool.

An important point to note from the stateless session bean lifecycle is that since beans are allocated from and returned to the pool on a per-invocation basis, stateless session beans are extremely performance friendly and a relatively small number of bean instances can handle a large number of virtually concurrent clients.

As you know, there are two types of stateless session bean lifecycle callback methods: (1) callbacks that are invoked when the PostConstruct event occurs immediately after a bean instance is created and set up, and all the resources are injected; and (2) callbacks that are invoked when the PreDestroy event occurs, right before the bean instance is retired and removed from the pool. Note that you can have multiple PostConstruct and PreDestroy callbacks for a given bean (although this is seldom used) in a class or in a separate interceptor class (discussed in topic 5).

In listing 3.1, the lifecycle callback methods embedded in the bean are initialize and cleanup. Callbacks must follow the pattern of void <METHOD>(). Unlike business methods, callbacks cannot throw checked exceptions (any exception that doesn’t have java.lang.RuntimeException as a parent).

Typically, these callbacks are used for allocating and releasing injected resources that are used by the business methods, which is exactly what we do in our example of BidManagerBean in listing 3.1. In listing 3.1 we open and close connections to the database using an injected JDBC data source.

Recall that the addBid method in listing 3.1 inserted the new bid submitted by the user. The method created a java.sql.Statement from an open JDBC connection and used the statement to insert a record into the bids table. The JDBC connection object used to create the statement is a classic heavy-duty resource. It is expensive to open and should be shared across calls whenever possible. It can hold a number of native resources, so it is important to close the JDBC connection when it is no longer needed. We accomplish both these goals using callbacks as well as resource injection.

In listing 3.1, the JDBC data source from which the connection is created is injected using the @Resource annotation. We explore injecting resources using the @Resource annotation in topic 5; for now, this is all that you need to know. Let’s take a closer look at how we used the callbacks in listing 3.1.

PostConstruct callback

The setDataSource method saves the injected data source in an instance variable. After injecting all resources, the container checks whether there are any designated PostConstruct methods that need to be invoked before the bean instance is put into the pool. In our case, we mark the initialize method in listing 3.1 with the @PostConstruct annotation:

tmp2478_thumb

Since bean instances from the pool are assigned randomly for each method invocation, trying to store client-specific state across method invocations is useless

tmp2479_thumb

In the initialize method, we create a java.sql.Connection from the injected data source and save it into the connection instance variable used in addBid each time the client invokes the method.

PreDestroy callback

At some point the container decides that our bean should be removed from the pool and destroyed (perhaps at server shutdown). The PreDestroy callback gives us a chance to cleanly tear down bean resources before this is done. In the cleanup method marked with the @PreDestroy annotation in listing 3.1, we tear down the open database connection resource before the container retires our bean:since the same bean instance may not be used for subsequent calls by the same client. On the other hand, stateful session beans, which we’ll discuss next, are ideally suited for this situation.

Next post:

Previous post: