| Lesson 5 | Stateless and Stateful Session Beans |
| Objective | Distinguish stateless and stateful session beans in Jakarta Enterprise Beans. |
Session beans are managed business components provided by Jakarta Enterprise Beans. In Jakarta EE 11, the key difference between a stateless session bean and a stateful session bean is not how a client obtains a remote object or communicates through legacy middleware. The important distinction is whether the component retains client-specific conversational state between method invocations.
A stateless session bean performs operations that do not depend on information retained from a previous call by the same client. The container can therefore maintain a pool of stateless bean instances and route incoming calls to available instances. A stateful session bean, in contrast, represents a conversation with a particular client and can retain information in instance fields from one method invocation to the next.
Both types run in a managed environment. The Jakarta EE runtime can provide dependency injection, declarative transactions, security, interceptors, persistence integration, lifecycle services, and other enterprise facilities. The choice between stateless and stateful should therefore be based primarily on the application's state and conversation requirements.
A stateless session bean is declared with the @Stateless annotation. It is designed for operations that
do not require the bean to remember client-specific conversational information after a method invocation completes.
Each request should contain, or provide access to, the information necessary to perform the requested operation.
This does not mean that a stateless bean can never have instance fields. An instance can use fields internally, and values may remain in those fields while the instance stays in the container's pool. Application code must not, however, depend on those values representing one client's state during a later invocation. A subsequent call from the same client may be handled by a different bean instance, while the original instance may later serve another client.
This property makes stateless beans well suited to service operations such as calculations, validation, order submission, database updates, payment orchestration, inventory checks, and other independent units of business logic. Because instances are reusable, the container can serve many clients with a managed pool rather than maintaining a dedicated component instance for every client conversation.
import jakarta.ejb.Stateless;
import java.math.BigDecimal;
@Stateless
public class TaxService {
public BigDecimal calculateTax(Order order) {
// Independent operation; no client-specific conversational state.
return order.subtotal().multiply(new BigDecimal("0.07"));
}
}
The supporting Order type is abbreviated here for teaching clarity. The important design feature is
that calculateTax() can perform its work from the information supplied to the method. It does not
depend on a value remembered from an earlier request by the same client.
A stateful session bean is declared with @Stateful. Unlike a stateless bean, a stateful bean preserves
conversational state for a client across multiple business method calls. The container maintains the association
between the client conversation and the stateful bean instance for the lifetime of that conversation.
A common use case is a multi-step workflow. For example, a checkout process may collect selected items during one method call, shipping information during another, and payment choices during another. The stateful component can retain temporary conversation data while the user progresses through the process.
import jakarta.ejb.Stateful;
import jakarta.ejb.StatefulTimeout;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Stateful
@StatefulTimeout(value = 20, unit = TimeUnit.MINUTES)
public class CheckoutConversation {
private final List<String> itemIds = new ArrayList<>();
public void addItem(String itemId) {
itemIds.add(itemId);
}
}
The @StatefulTimeout annotation allows the application to specify how long an idle stateful
conversation may remain before the container is allowed to remove it. Stateful beans may also define an appropriate
removal method with @Remove when the application has an explicit point at which the conversation
finishes.
Because each active stateful conversation requires associated runtime state, stateful beans usually require more container resources than stateless beans. A Jakarta Enterprise Beans implementation may use passivation to move an eligible inactive stateful instance out of active memory and later activate it when needed. Passivation is a lifecycle optimization, not a durable storage system.
If information must survive application restarts, server failures, or the end of a user's conversation, that information should be stored in durable storage. Jakarta Persistence, a database, or another durable data service is appropriate for business records that must outlive the stateful bean.
| Characteristic | Stateless Session Bean | Stateful Session Bean |
|---|---|---|
| Client-specific conversational state | Does not retain client-specific conversational state between method calls | Retains conversational state for an associated client across method calls |
| Instance management | Instances are reusable and commonly managed in a pool | An instance is associated with a client conversation |
| Scalability | Generally efficient for large numbers of independent client requests | Consumes additional resources because conversational state must be retained |
| Lifecycle | The container creates, pools, reuses, and removes instances | The container manages creation, conversational association, timeout, removal, and possible passivation |
| Passivation | Not used to preserve a client conversation | Eligible beans may be passivated and later activated by the container |
| Typical use cases | Validation, calculations, service operations, database updates, orchestration | Multi-step workflows, configurators, temporary carts, and client-specific conversations |
| Transactions | Can participate in Jakarta Transactions | Can participate in Jakarta Transactions |
| Durable application data | Store durable data through Jakarta Persistence or another durable store | Conversational fields are not durable database persistence; durable data should be stored separately |
Older Enterprise JavaBeans architectures often described clients locating enterprise components through naming services and communicating through distributed-object technologies. That is not the normal architecture for a modern browser-based or HTTP service application.
A browser, mobile application, or external service commonly sends an HTTPS request to an application endpoint such as a Servlet or Jakarta RESTful Web Services resource. That managed endpoint can then invoke application services inside the Jakarta EE runtime. The internal service may be a CDI managed bean or a Jakarta Enterprise Bean, depending on the services and lifecycle semantics required by the application.
CDI dependency injection is the ordinary mechanism for wiring managed application components together. A CDI managed bean is not automatically a session bean. CDI and Jakarta Enterprise Beans are different component models, although Jakarta EE integrates them so that session beans can participate in the dependency injection environment.
Jakarta Enterprise Beans can expose a no-interface view, a local business interface, or a remote business interface where appropriate. A remote business interface is useful when remote enterprise-component access is genuinely required, but it should not be confused with the normal HTTP architecture used by web clients.
JNDI remains available as a naming and resource mechanism, particularly for configured resources and integration scenarios. It is not a requirement that every modern client locate a session bean through JNDI before using an application.
Both stateless and stateful session beans can participate in declarative transaction management. Jakarta Transactions defines the transaction model used by Jakarta EE components. A business method can execute within a transaction boundary managed by the runtime, allowing multiple related database operations to succeed or roll back as a unit.
Jakarta Persistence provides the object-relational persistence model used for durable entity data. A session bean may invoke persistence operations inside a transaction while the persistence context tracks the affected entities. This separates temporary conversational state from durable business state.
For example, a stateful checkout component might temporarily retain selected product identifiers while a customer completes several steps. Once the order is confirmed, an application service can create persistent order and order item entities within a transaction. The stateful component's temporary list is part of the conversation; the database records represent the durable business result.
The same principle applies to stateless components. Stateless does not mean that an operation cannot update stored information. It means that the bean itself does not rely on client-specific conversational state between calls. A stateless service can read and modify large amounts of persistent shared data while still remaining stateless from the client's perspective.
Jakarta Enterprise Beans also defines @Singleton as a third session-bean type. A singleton session bean
represents one shared component instance for an application and can be useful for application-wide coordination or
shared managed state. It is different from a stateful session bean because its state is shared at the application
level rather than being dedicated to one client conversation.
Choose a stateless session bean when each operation can be completed independently and later calls do not need client-specific information retained by the component. This design usually provides the simplest scaling model because the container can distribute calls among reusable pooled instances.
Choose a stateful session bean when the application genuinely has a server-side conversation whose intermediate state must survive across several calls from the same client. A stateful bean is particularly useful when that conversation has a clear beginning, a bounded lifetime, and a clear completion point.
Do not choose a stateful bean simply because an application stores data. Persistent customer records, orders, accounts, products, and other durable information belong in an appropriate persistent store. Stateful session beans are intended for conversational state, not as replacements for Jakarta Persistence or database storage.
Likewise, do not use Jakarta Enterprise Beans merely because an application needs dependency injection. CDI managed beans provide a general-purpose component model for application services. Jakarta Enterprise Beans are appropriate when their defined session-bean semantics and enterprise services provide a concrete benefit.
The essential distinction between stateless and stateful session beans is conversational state. A stateless session bean does not preserve client-specific conversational state between invocations, allowing its instances to be pooled and reused efficiently. A stateful session bean maintains an association with a client conversation and preserves temporary state across multiple calls.
Both component types can use Jakarta EE services including dependency injection, Jakarta Transactions, Jakarta Persistence integration, security, and interceptors. Durable business information should be stored using persistence technology rather than relying on stateful bean fields. Modern HTTP clients normally enter the application through HTTP endpoints, while CDI and Jakarta Enterprise Beans provide managed component models inside the Jakarta EE application.