Chapter 3. Resource Management and the Primary Services

Chapter 2 discussed the basic architecture of Enterprise JavaBeans, including the relationship between the bean class, the component interfaces, the EJB object and EJB home, and the EJB container. These architectural components define a common model for distributed server-side components in component transaction monitors.

One of the reasons why CTMs are such great distributed object platforms is that they do more than just distribute objects: they also 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, threads, database connections, processing power, and more. 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, but 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.

With the introduction of message-driven beans in EJB 2.0, Enterprise JavaBeans goes beyond most CTMs by expanding the platform’s responsibilities to include managing asynchronous messaging components. CTMs have historically been responsible only for managing RMI-based distributed objects. While the method of access is different for message-driven beans, EJB is still responsible for managing the primary services for message-driven beans just as it does for session and entity beans.

This chapter discusses both the resource-management facilities and the primary services that are available to Enterprise JavaBeans.

Resource Management

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

Instance Pooling

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 database connections needed, which reduces resource consumption and increases throughput. Pooling and reusing database connections is less expensive than creating and destroying connections as needed. Most EJB containers 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. It is also less expensive to reuse pooled instances than to frequently create and destroy instances.

As you already know, EJB clients of session and entity beans interact with these types of enterprise beans through the remote and, for EJB 2.0, local interfaces that are implemented by EJB objects. Client applications never have direct access to the actual session or entity bean. Instead, they interact with EJB objects, which wrap bean instances. Similarly, JMS clients in EJB 2.0 never interact with message-driven beans directly. They send messages that are routed to the EJB container system. The EJB container then delivers these messages to the proper message-driven instance.

Instance pooling leverages indirect access to enterprise 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 enterprise bean for each client. The server can keep a much smaller number of enterprise beans around to do the work, reusing each enterprise bean instance to service different requests. Although this sounds like a resource drain, when done correctly, it greatly reduces the resources actually required to service all the client requests.

The entity bean life cycle

To understand how instance pooling works for RMI components (session and entity beans), 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. Entity beans exist in one of three states:

No state

When a bean instance is in this state, it has not yet been instantiated. We identify this state to provide a beginning and an end for the life cycle of a bean instance.

Pooled state

When an instance is in this state, it has been instantiated by the container but has not yet been associated with an EJB object.

Ready state

When a bean instance is in this state, it has been associated with an EJB object and is ready to respond to business method invocations.

Overview of state transitions

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. Enterprise beans also have a JNDI context called the environment naming context. The function of the environment naming context 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 or local reference 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 results in an EJB object wrapping a bean instance and servicing a client.

A bean moves from the instance pool to the Ready state

Figure 3-1. A bean moves from the instance pool to the Ready state

When a bean instance moves into the Ready state, the EJBContext takes on new meaning. The EJBContext 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 enterprise beans, or when it needs to create, locate, or remove beans of its own class. So the EJBContext 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.[11] 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.

After the bean instance returns to the instance pool, it is again available to service a new client request. Figure 3-2 illustrates the life cycle of a bean instance.

Life cycle of a bean instance

Figure 3-2. 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.

Instance swapping

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 Figure 3-3(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 (Figure 3-3(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 and is serviced by instance B (Figure 3-3(d)).

Stateless session beans in a swapping strategy

Figure 3-3. Stateless session beans in a swapping strategy

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 (first in, first out) and LIFO (last in, first out). The FIFO strategy places instances in a queue, where they wait in line to service EJB objects. LIFO uses a 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.

EJB 2.0: Message-driven beans and instance pooling

Message-driven beans, like stateless session beans, do not maintain state specific to a client request, which makes them an excellent component for instance pooling.

In most EJB containers, each type of message-driven bean has its own instance pool that is used to service incoming messages. Message-driven beans subscribe to a specific message destination, which is a kind of address used when sending and receiving messages. When a JMS client sends an asynchronous message to a specific destination, the message is delivered to the EJB containers of message-driven beans that subscribe to that destination. The EJB container will first determine which message-driven bean subscribes to that destination, then choose an instance of that type from the instance pool to process the message. Once the message-driven bean instance has finished processing the message (when the onMessage() method returns), the EJB container will return the instance to its instance pool. An EJB container can process hundreds, possibly thousands, of messages concurrently by leveraging instance pools. Figure 3-4 illustrates how client requests are processed by an EJB container.

Message-driven bean instance pooling

Figure 3-4. Message-driven bean instance pooling

In Figure 3-4, the top JMS client delivers a message to Destination A and the bottom JMS client delivers a message to Destination B. The EJB container chooses an instance of MessageDrivenBean_1 to process the message intended for Destination A and an instance of MessageDrivenBean_2 to process the message intended for Destination B. The bean instances are removed from the pool and assigned and used to process the messages.

A moment later, the middle JMS client sends a message to Destination B. At this point, the first two messages have already been processed and the container is returning the instances to their respective pools. As the new message comes in, the container chooses a new instance of MessageDrivenBean_2 to process the message.

Message-driven beans are always deployed to process messages from a specific destination. In the above example, instances of MessageDrivenBean_1 process messages only for Destination A, while instances of MessageDrivenBean_2 process messages only for Destination B. Several messages for the same destination can be processed at the same time. If, for example, a hundred messages for Destination A all arrived at the same time from a hundred different JMS clients, the EJB container would simply choose a hundred instances of MessageDrivenBean_1 to process the incoming messages; each instance is assigned a message.

The ability to concurrently process messages makes message-driven beans extremely powerful enterprise beans, on the same level as session and entity beans. They are truly first-class components and are an important addition to the Enterprise JavaBeans platform.

The Activation Mechanism

Unlike other enterprise beans, stateful session beans maintain state between method invocations. This is called conversational state 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, unlike stateless session, entity, and message-driven beans, do not participate in instance pooling. 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 reference, 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-5 shows activation and passivation of a stateful bean. In Figure 3-5(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-5(b), the bean has been passivated and its state preserved. Here, the EJB object is not associated with a bean instance. In Figure 3-5(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 with the state held relative to the EJB object.

The passivation and activation processes

Figure 3-5. The passivation and activation processes

The exact mechanism for activating and passivating stateful beans is up to the vendor, but each stateful bean is serializable and thus provides at least one way of temporarily preserving its 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, and so on. 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 life-cycle callback methods discussed in Chapter 2. The ejbActivate() and ejbPassivate() methods, respectively, notify the stateful bean instance that it is about to be activated or passivated. 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. EJB also requires that the references to the JNDI environment context, component interfaces, and the UserTransaction bean be maintained through passivation.

Unlike stateful beans, entity beans do not have conversational state that needs to be serialized; instead, the state of each entity bean instance 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.



[11] The EJBHome, EJBLocalHome, EJBObject, and EJBLocalObject interfaces all define methods that can be used to remove a bean.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset