As organizations strive to develop collaborative software solutions, it is not uncommon to discover that an enterprise software system does not actually exist or function as a single software entity. Instead, there is a high degree of probability that the enterprise system actually comprises numerous independent software subsystems, each of which can exist on separate software platforms with unique operational boundaries. The communication mechanism and the development plumbing effort involved to enable applications to communicate between themselves really depend on the interoperability of their respective implementation technologies. For example, the Remote Procedure Call (RPC) model is a viable communication solution between applications that have accessible and well-defined interfaces for processing client requests . The downside of the RPC model is that, regardless of whether communication between applications is enabled through an application adapter, you are implementing tight integration at the interface level (object class/ methods ) between possibly autonomous applications. Also, communication could be limited to synchronous interactions; for example, Enterprise JavaBean (EJB) clients use the home and remote interfaces to make synchronous RMI calls to their target EJB server. The client invoking the EJB call pauses its processing (blocks) until the EJB server returns processing control to the client through a response. When loose coupling, reliability, and asynchronous processing are requirements between J2EE applications/ components and Enterprise Information Systems (EISs), leveraging an intermediary messaging system that is a Java Messaging Service (JMS) provider and also interoperable with the EIS is probably your best option for centralizing communication flow through the production and consumption of messages. Note A JMS provider implements the JMS API, a set of standard interfaces that define how a JMS client accesses the facilities of a messaging service. This chapter uses a lot of concepts related to messaging domains and the JMS API. If you're not familiar with either topic, reading Chapter 15, "The Java Messaging Service (JMS)," is recommended before proceeding with this chapter. By leveraging a messaging model,
A shortfall of the EJB 1.1 specification is that it did not provide an EJB type for handling asynchronous communications. However, a Java client could be used as a synchronous or asynchronous message listener for a JMS destination, which made it possible to route messages to an EJB for processing. Note Any J2EE component can send or synchronously receive a JMS message. One of the goals of the EJB 2.0 specification is to provide a tighter integration with the JMS API, which was successfully achieved by introducing the message-driven bean (MDB) , a new EJB type that can consume asynchronous JMS messages by listening to a queue or subscribing to a topic. By fulfilling the consumer side of the JMS messaging model, MDBs are asynchronous message listeners/consumers that are associated with only one queue or topic. Figure 22.1 illustrates the partition of component functionality provided by J2EE and the EJB 2.0 specification. Figure 22.1. The functionality provided by J2EE and the EJB 2.0 specification.
The Characteristics of Message-Driven BeansAs an EJB type, MDBs reside within the context of an EJB container and, similar to standard JMS message listeners, cannot interact directly with their JMS clients because they do not have a home or remote interface. For this reason, MDBs are considered anonymous because they have no client-visible identity. Similar to stateless session beans, MDB instances also have no conversational state, which implies that all bean instances are equivalent when they are not involved in servicing a client message. This characteristic permits the EJB container to pool and create multiple instances of the same MDB based on the throughput of messages in the MDB's JMS destination, hence enabling the concurrent consumption of messages, as shown in Figure 22.2. Figure 22.2. The concurrent consumption of messages by an MDB in an EJB container.
A client accesses an MDB through JMS by sending messages to a JMS destination (queue or topic) for which the MDB class is assigned as a message listener. MDBs are associated with a specific JMS destination via their deployment descriptors. Note Standard JMS message listeners receive messages asynchronously by implementing javax.jms.MessageListener with the onMessage() method. When a message arrives in a JMS destination targeted for an MDB, the JMS provider and the EJB container automatically collaborate to deliver the message to the MDB. One instance from the MDB bean pool is selected to handle the message. Similar to a standard JMS message listener, an MDB contains an onMessage() method that is called automatically when a message arrives. However, different messages can be processed concurrently by different MDB instances, which provides performance and scalability benefits. After an MDB consumes a message, it can process the message or pass the message to another EJB type for processing, as shown in Figure 22.3. Figure 22.3. An example of processing an MDB.
The Value Proposition of Message-Driven BeansThe primary benefit of using MDBs for asynchronous consumption of messages is derived from MDBs existing completely in the context of an EJB container and, therefore, being able to leverage EJB services the container provides. For example, the WebLogic EJB container provides a standard set of services, such as concurrency control, persistence, security, transaction management, locking, clustering, and complete JMS infrastructure support, which would otherwise need to be configured in code and via the Administration Console for a standard JMS Listener. Note MDBs can initiate Container-Managed and Bean-Managed Transactions, which are discussed in "An Overview of Message-Driven Bean Transactions" later in this chapter. Although an MDB can serve only one JMS destination, its stateless nature allows the WebLogic EJB container to create multiple MDB instances as necessary to process large volumes of messages concurrently, hence providing a scalable mechanism for concurrent consumption/processing of messages. In contrast, you would have to configure the standard JMS Listener class to be a member of a serverwide session pool via the Administration Console. Note Instance pooling within the EJB container implies that messages are not received or processed in sequential order, although individual onMessage() calls to an MDB instance are serialized. As you will learn later in the "The Life Cycle of a Message-Driven Bean" section, WebLogic Server maintains a free pool of EJBs for every MDB class to expedite processing asynchronous messages. Another benefit of using MDBs is that they inherit the write-once, deploy- anywhere quality of EJBs, as the associated JMS destination and server resource attributes are assigned only at deployment time. This provides better portability of MDBs between different implementations of the EJB container. MDBs are suitable for use over standard JMS Consumers in the following situations:
One constraint of using MDBs compared to standard JMS Listeners is that you can associate an MDB only to a single JMS destination (queue or topic). If you require a single JMS Consumer to process messages from multiple JMS destinations, you can use a standard JMS Consumer or deploy MDB classes for each JMS destination. Differences Between MDBs and Other Bean TypesEven though an MDB is a bean type that can mimic the behavior of stateless session bean instances at times (pooling) and, like other EJBs, live within the boundaries of an EJB container, the following differences between MDBs and the other bean types (session and entity) further clarify their unique message consumption characteristics:
Table 22.1 summarizes the differences between message-driven, session, and entity beans. Table 22.1. Summary of EJB Type Characteristics
|