Chapter 2, "Architectural Overview" discussed the basic architecture of Enterprise JavaBeans (EJB), including the relationship between the bean class, remote interfaces, the EJB object and EJB home, and the EJB server. These architectural components define a common model for distributed server-side components in component transaction monitors (CTMs).
One of the reasons CTMs are such great distributed object platforms is that they do more than just distribute objects: they manage the resources used by distributed objects. CTMs are designed to manage thousands, even millions, of distributed objects simultaneously. To be this robust, CTMs must be very smart resource managers, managing how distributed objects use memory and processing power. EJB recognizes that some of the resource management techniques employed by CTMs are very common, and it defines interfaces that help developers create beans that can take advantage of these common practices.
EJB CTMs are also great distributed object brokers. Not only do they help clients locate the distributed objects they need, they also provide many services that make it much easier for a client to use the objects correctly. CTMs commonly support six primary services: concurrency, transaction management, persistence, object distribution, naming, and security. These services provide the kind of infrastructure that is necessary for a successful three-tier system.
This chapter discusses both the resource management facilities and the primary services that are available to Enterprise JavaBeans.
One of the fundamental benefits of using EJB servers is that they are able to handle heavy workloads while maintaining a high level of performance. A large business system with many users can easily require thousands of objects--even millions of objects--to be in use simultaneously. As the number of interactions among these objects increase, concurrency and transactional concerns can degrade the system's response time and frustrate users. EJB servers increase performance by synchronizing object interactions and sharing resources.
There is a relationship between the number of clients connected and the number of distributed objects that are required to service them. As client populations increase, the number of distributed objects and resources required increases. At some point, the increase in the number of clients will impact performance and diminish throughput. EJB explicitly supports two mechanisms that make it easier to manage large numbers of beans at runtime: instance pooling and activation.
The concept of pooling resources is nothing new. A commonly used technique is to pool database connections so that the business objects in the system can share database access. This trick reduces the number of connections needed, which reduces resource consumption and increases throughput. Pooling and reusing database connections is less expensive than creating and destroying connections as needed. Some CTMs also apply resource pooling to server-side components; this technique is called instance pooling. Instance pooling reduces the number of component instances, and therefore resources, needed to service client requests. In addition, it is less expensive to reuse pooled instances than to frequently create and destroy instances.
As you already know, EJB clients interact with the remote interfaces that are implemented by EJB objects. Client applications never have direct access to the actual bean. Instead, they interact with EJB objects, which wrap bean instances. Instance pooling leverages indirect access to beans to provide better performance. In other words, since clients never access beans directly, there's no fundamental reason to keep a separate copy of each bean for each client. The server can keep a much smaller number of beans around to do the work, copying data into or out of them as needed. Although this sounds like a resource drain, when done correctly, it greatly reduces the resources actually required at any one time.
To understand how instance pooling works, let's examine the life cycle of an entity bean. EJB defines the life cycle of an entity bean in terms of its relationship to the instance pool. An entity bean exists in one of three states:
When a bean instance is in this state, it has not been instantiated yet. We identify this state to provide a beginning and an end for the life cycle of a bean instance.
When an instance is in the pooled state, it has been instantiated by the container but has not yet been associated with an EJB object.
A bean instance in this state has been associated with an EJB object and is ready to respond to business method invocations.
Each EJB vendor implements instance pooling for entity beans differently, but all instance pooling strategies attempt to manage collections of bean instances so that they are quickly accessible at runtime. To create an instance pool, the EJB container creates several instances of a bean class and then holds onto them until they are needed. As clients make business method requests, bean instances from the pool are assigned to the EJB objects associated with the clients. When the EJB object doesn't need the instance any more, it's returned to the instance pool. An EJB server maintains instance pools for every type of bean deployed. Every instance in an instance pool is equivalent ; they are all treated equally. Instances are selected arbitrarily from the instance pool and assigned to EJB objects as needed.
Soon after the bean instance is instantiated and placed in the pool, it's given a reference to a javax.ejb.EJBContext provided by the container. The EJBContext provides an interface that the bean can use to communicate with the EJB environment. This EJBContext becomes more useful when the bean instance moves to the Ready State.
NOTE
EJB 1.1 has extended the bean's interface with its environment to include a JNDI context called the environment context. The function of the environment context in EJB 1.1 is not critical to this discussion and will be addressed in more detail later in the chapter.
When a client uses an EJB home to obtain a remote interface to a bean, the container responds by creating an EJB object. Once created, the EJB object is assigned a bean instance from the instance pool. When a bean instance is assigned to an EJB object, it officially enters the Ready State. From the Ready State, a bean instance can receive requests from the client and callbacks from the container. Figure 3-1 shows the sequence of events that result in an EJB object wrapping a bean instance and servicing a client.
When a bean instance moves into the Ready State, the EntityContext takes on new meaning. The EntityContext provides information about the client that is using the bean. It also provides the instance with access to its own EJB home and EJB object, which is useful when the bean needs to pass references to itself to other instances, or when it needs to create, locate, or remove beans of its own class. So the EntityContext is not a static class; it is an interface to the container and its state changes as the instance is assigned to different EJB objects.
When the client is finished with a bean's remote reference, either the remote reference passes out of scope or one of the bean's remove methods is called.[1] Once a bean has been removed or is no longer in scope, the bean instance is disassociated from the EJB object and returned to the instance pool. Bean instances can also be returned to the instance pool during lulls between client requests. If a client request is received and no bean instance is associated with the EJB object, an instance is retrieved from the pool and assigned to the EJB object. This is called instance swapping.
[1] Both the EJBHome and the EJBObject interfaces define methods that can be used to remove a bean.
After the bean instance returns to the instance pool, it is again available to service a new client request. Chapter 3, "Resource Management and the Primary Services" illustrates the complete life cycle of a bean instance.
The number of instances in the pool fluctuates as instances are assigned to EJB objects and returned to the pool. The container can also manage the number of instances in the pool, increasing the count when client activity increases and lowering the count during less active periods.
Stateless session beans offer a particularly powerful opportunity to leverage instance pooling. A stateless session bean does not maintain any state between method invocations. Every method invocation on a stateless session bean operates independently, performing its task without relying on instance variables. This means that any stateless session instance can service requests for any EJB object of the proper type, allowing the container to swap bean instances in and out between method invocations made by the client.
Figure 3-3 illustrates this type of instance swapping between method invocations. In Chapter 3, "Resource Management and the Primary Services"(a), instance A is servicing a business method invocation delegated by EJB object 1. Once instance A has serviced the request, it moves back to the instance pool (Chapter 3, "Resource Management and the Primary Services"(b)). When a business method invocation on EJB object 2 is received, instance A is associated with that EJB object for the duration of the operation (Figure 3-3(c)). While instance A is servicing EJB object 2, another method invocation is received by EJB object 1 from the client, which is serviced by instance B (Figure 3-3(d)).
Using this swapping strategy allows a few stateless session bean instances to serve hundreds of clients. This is possible because the amount of time it takes to perform most method invocations is substantially shorter than the pauses between method invocations. The periods in a bean instance's life when it is not actively servicing the EJB object are unproductive; instance pooling minimizes these inactive periods. When a bean instance is finished servicing a request for an EJB object, it is immediately made available to any other EJB object that needs it. This allows fewer stateless session instances to service more requests, which decreases resource consumption and improves performance.
Stateless session beans are declared stateless in the deployment descriptor. Nothing in the class definition of a session bean is specific to being stateless. Once a bean class is deployed as stateless, the container assumes that no conversational state is maintained between method invocations. So a stateless bean can have instance variables, but because bean instances can be servicing several different EJB objects, they should not be used to maintain conversational state.
Implementations of instance pooling vary, depending on the vendor. One way that instance pooling implementations often differ is in how instances are selected from the pool. Two of the common strategies are FIFO and LIFO. The FIFO (first in, first out) strategy places instances in a queue, where they wait in line to service EJB objects. The LIFO (last in, first out) uses more of stack strategy, where the last bean that was added to the stack is the first bean assigned to the next EJB object. Figure 3-3 uses a LIFO strategy.
Unlike stateless session beans, stateful session beans maintain state between method invocations. This is called conversationalstate because it represents the continuing conversation with the stateful session bean's client. The integrity of this conversational state needs to be maintained for the life of the bean's service to the client. Stateful session beans do not participate in instance pooling like stateless session beans and entity beans. Instead, activation is used with stateful session beans to conserve resources. When an EJB server needs to conserve resources, it can evict stateful session beans from memory. This reduces the number of instances maintained by the system. To passivate the bean and preserve its conversational state, the bean's state is serialized to a secondary storage and maintained relative to its EJB object. When a client invokes a method on the EJB object, a new stateful instance is instantiated and populated from the passivated secondary storage.
Passivation is the act of disassociating a stateful bean instance from its EJB object and saving its state. Passivation requires that the bean instance's state be held relative to its EJB object. After the bean has been passivated, it is safe to remove the bean instance from the EJB object and evict it from memory. Clients are completely unaware of the deactivation process. Remember that the client uses the bean's remote interface, which is implemented by an EJB object, and therefore does not directly communicate with the bean instance. As a result, the client's connection to the EJB object can be maintained while the bean is passivated.
Activating a bean is the act of restoring a stateful bean instance's state relative to its EJB object. When a method on the passivated EJB object is invoked, the container automatically instantiates a new instance and sets its fields equal to the data stored during passivation. The EJB object can then delegate the method invocation to the bean as normal. Figure 3-4 shows activation and passivation of a stateful bean. In Chapter 3, "Resource Management and the Primary Services"(a), the bean is being passivated. The state of instance B is read and held relative to the EJB object it was serving. In Figure 3-4(b), the bean has been passivated and its state preserved. Here, the EJB object is not associated with a bean instance. In Figure 3-4(c), the bean is being activated. A new instance, instance C, has been instantiated and associated with the EJB object, and is in the process of having its state populated. The instance C is populated with the state held relative to the EJB object.
The exact mechanism for activating and passivating stateful beans is up to the vendor, but all stateful beans are serializable and thus provide at least one way of temporarily preserving their state. While some vendors take advantage of the Java serialization mechanism, the exact mechanism for preserving the conversational state is not specified. As long as the mechanism employed follows the same rules as Java serialization with regard to transitive closure of serializable objects, any mechanism is legal. Because Enterprise JavaBeans also supports other ways of saving a bean's state, the transient property is not treated the same when activating a passivated bean as it is in Java serialization. In Java serialization, transient fields are always set back to the initial value for that field type when the object is deserialized. Integers are set to zero, Booleans to false, object references to null, etc. In EJB, transient fields are not necessarily set back to their initial values but can maintain their original values, or any arbitrary value, after being activated. Care should be taken when using transient fields, since their state following activation is implementation specific.
The activation process is supported by the state-management callback methods discussed in Chapter 2, "Architectural Overview". Specifically, the ejbActivate() and ejbPassivate() methods notify the stateful bean instance that it is about to be activated or passivated, respectively. The ejbActivate() method is called immediately following the successful activation of a bean instance and can be used to reset transient fields to an initial value if necessary. The ejbPassivate() method is called immediately prior to passivation of the bean instance. These two methods are especially helpful if the bean instance maintains connections to resources that need to be manipulated or freed prior to passivation and reobtained following activation. Because the stateful bean instance is evicted from memory, open connections to resources are not maintained. The exceptions are remote references to other beans and the SessionContext, which must be maintained with the serialized state of the bean and reconstructed when the bean is activated.
NOTE
EJB 1.1 also requires that the references to the JNDI environment context, home interfaces, and the UserTransaction be maintained through passivation.
Entity beans do not have conversational state that needs to be serialized like stateful beans; instead, the state of entity bean instances is persisted directly to the database. Entity beans do, however, leverage the activation callback methods (ejbActivate() and ejbPassivate()) to notify the instance when it's about to be swapped in or out of the instance pool. The ejbActivate() method is invoked immediately after the bean instance is swapped into the EJB object, and the ejbPassivate() method is invoked just before the instance is swapped out.
Copyright © 2001 O'Reilly & Associates. All rights reserved.