MDB: Difference between revisions
Line 58: | Line 58: | ||
<tt>@PreDestroy</tt> | <tt>@PreDestroy</tt> | ||
Note that if the MDB implements the <tt>MessageDrivenBean</tt> interface, this annotation can only be applied to the <tt>ejbRemove()</tt> method. | |||
==Dependency Injection== | ==Dependency Injection== |
Revision as of 23:38, 17 March 2017
Internal
Overview
A Message-Driven Bean (MDB) is an asynchronous message consumer, invoked by the container as a result of the arrival of a message at the JMS destination serviced by the message-driven bean.
To a client, an MDB is a message consumer that implements some business logic running on the server. A client accesses an MDB by sending messages to the JMS destination associated with the MDB container of that type. MDBs are anonymous. They have no client-visible identity. MDB instances have no conversational state either, meaning they do not maintain state for a specific client. All bean instances are equivalent when they are not involved in servicing a client message. An MDB instance is created by the container to handle the processing of the messages for which the MDB is the consumer. Its lifetime is controlled by the container.
API
The @MessageDriven Annotation
An MDB must be annotated with the @javax.ejb.MessageDriven annotation, or denoted in its deployment descriptor as a message driven bean.
activationConfig
messageListenerInterface
Code
An MDB must implement the appropriate listener interface for the messaging type the MDB supports. If the MDB implements javax.jms.MessageListener interface, that distinguishes the MDB as a JMS MDB. If the class does not implement the interface, the MDB must specify the message listener interface using the @MessageDriven annotation, with its "messageListenerInterface" element, or the messaging-type deployment descriptor element. The class must have a public constructor with no arguments.
The MessageDrivenBean interface, which was required by previous EJB versions, is currently optional. The main role of this interface was to allow the MDB to access container services, and currently, this need is fulfilled by the optionally injected MessageDriventContext.
The onMessage() method of the message listener is called by the container when a message arrives. The method must contain the business logic to handle the message.
It is the container's responsibility to insure that only one thread can be executing an instance at any time.
Deployment Descriptor
messaging-type
Examples
The simplest possible working MDB example is available here:
Another example that showcases most of the configuration and API details discussed in this article is available here:
Transactional Context
By default, without declaring anything, an MDB will be executed with the context of a container managed transaction.
Security Context
The container enforces declarative security, so only the calls with appropriate security credentials can be made into the MDBs. The MDB have access to their security context via the MessageDrivenContext's security related methods, such as getCallerPrincipal().
Relationship with the Container and Lifecycle
It is the container's responsibility to instantiate the MDB instances, manage their life cycle, notify the MDB instances when bean action may be necessary and provide security, concurrency, transactions and other services. The MDB instances need not concern about scalability and the concurrent processing of a large number of messages: it is the container's responsibility to instantiate a large enough MDB instance number and handle the message distribution to them. All MDB instances are equivalent, a client message can be delivered to any available instance.
Lifecycle
@PostConstruct
@PreDestroy
Note that if the MDB implements the MessageDrivenBean interface, this annotation can only be applied to the ejbRemove() method.
Dependency Injection
An MDB may use dependency injection mechanisms to acquire references to other objects in the environment. If the MDB uses dependency injection, the container will inject these reference after the bean instance is created and before the first invocation of the onMessage() method.
MessageDrivenContext
The MDB may declare interest in accessing services from the container by requesting a MessageDrivenContext to be injected into it (or, alternatively, by implementing the MessageDrivenBean interface):
@Resource private MessageDrivenContext context;
The MessageDrivenContext allows the MDB instance to interact with its transactional, security and JNDI contexts, among other things:
- Rollback the current transaction with setRollbackOnly(), or test the rollback status of the current transaction with getRollbackOnly(). Only MDBs with container-managed transaction can use this method.
- Get access to the javax.transaction.UserTransaction instance with getUserTransaction(). The UserTransaction object then can be used to interact with the on-going transaction and obtain the transaction status. Only MDBs with bean-managed transaction can use this method, otherwise an IllegalStateException is thrown on invocation.
- Get the java.security.Principal instance associated with the invocation with getCallerPrincipal().
- Access the JNDI via lookup().
- Get a javax.ejb.TimerService instance with getTimerService().
- Retrieve any interceptor/web service context associated with this invocation, with getContextData().
Client's Access to MDBs
Clients cannot access a specific MDB, they can only send messages to destinations serviced by MDBs.
A client looks up the destination in JNDI. The client's JNDI name space may be configured to include destinations serviced by MDBs installed in multiple containers located on multiple machines on a network. The actual locations of the MDBs are transparent to the clients sending messages into them.