Messaging concepts
Message-oriented middleware
Messaging models
- Point-to-Point
- There may be multiple producers and consumers, but only one consumer will process a given message.
- PTP message destinations are called queues.
- Publish-Subcribe
Introducing JMS
JMS is a deceptively small API to a very powerful technology. The JMS API is to messaging what the Java Database Connectivity (JDBC) API is to database access. JMS provides a standard way of accessing MOM in Java and is therefore an alternative to using product-specific APIs.
JMS Message interface
- Message Headers
JSMCorrelationIDJMSReplyToJMSMessageIDJMSTimestamp
- Message Properties
- Mesasge Body
Working with MDBs
MDBs are EJB components designed to consume asynchronous messages.
Why use MDBs
- Multithreading
- Simplified messaging code
- Robust message processing
- Starting message consumption
Developing a message consumer with MDB
Using the @MessageDriven annotation
@Target(value = {ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MessageDriven {
String name() default "";
Class messageListenerInterface default Object.class;
ActivationConfigProperty[] activationConfig() default {};
String mappedName();
String description(); }
name: specifies the name of the MDB if you need to explicitly assign it. If the name element is omitted, the code uses the name of the class
Implemeting the MessageListener
messageListenerInterface: most often you’ll omit this parameter and specify the interface using the Java implements keyword- Yet another option is to specify the
MessageListenerinterface through the XML deployment descriptor and leave this detail out of the code altogether:
- Yet another option is to specify the
<ejb-jar...>
<enterprise-beans>
<message-driven>
...
<messaging-type> javax.jms.MessageListener</messaging-type>
</message-driven>
</enterprise-beans>
</ejb-jar>
Using theActivationConfigProperty
@Target(value = {})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface ActivationConfigProperty {
String propertyName();
String propertyValue();
}
- Each activation property is a name–value pair that the underlying messaging provider understands and uses to set up the MDB.
Two of the most common JMS activation config- uration properties:
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/ShippingRequestQueue")
})
destinationType: property tells the container this JMS MDB is listening to a queue.destinationLookup: parameter specifies that you’re listening for messages arriving at a destination with the JNDI name
Activation properties for a JMS provider standardized by the JMS 2.0 spec
| Activation property | Description |
|---|---|
destinationLookup | The JNDI lookup of a javax.jms.Queue or a javax.jms.Topic. |
connectionFactoryLookup | The JNDI lookup of a javax.jms.ConnectionFactory, javax.jms.QueueConnectionFactory, or javax.jms.TopicConnectionFactory. |
acknowledgeMode | Auto-acknowledge (default) or Dups-ok-acknowledge. |
messageSelector | A message select to filter the messages the MDB receives. |
destinationType | javax.jms.Queue or javax.jms.Topic. |
subscriptionDurability | Applies only to destinationType=avax.jms.Topic. Values are either Durable or NonDurable (default). |
clientId | Sets the client identifier used when connecting to the JMS provider. |
subscriptionName | Applies only to destinationType=javax.jms.Topic. The name of the durable or non-durable subscription. |
Acknowledgement mode
Auto-acknowledge: The session acknowledges messages on your behalf in the backgroundDups-ok-acknowledge:
@ActivationConfigProperty {
propertyName="acknowledgeMode"
propertyValue="Dups-ok-acknowledge"
Subscription durability
If the MDB is listening on a topic, you can specify whether the topic subscription is durable or nondurable.
MessageConsumer orderSubscriber = session.createDurableSubscriber( orderTopic, "OrderProcessor");
From now on, all messages to the topic will be held until a consumer with the subscription ID OrderProcessor receives them. You can remove this subscription with the following code:
session.unsubscribe("OrderProcessor");
MDB to be a durable subscriber
@ActivationConfigProperty(
propertyName="destinationType",
propertyValue="javax.jms.Topic"),
@ActivationConfigProperty(
propertyName="subscriptionDurability",
propertyValue="Durable"
Message selector
The messageSelector property is the MDB parallel to applying a selector for a raw JMS consumer.
For example, you could specify in your MDB that you want to handle only fragile shipping requests as follows:
@ActivationConfigProperty(
propertyName="messageSelector"
propertyValue="Fragile is TRUE"
)
As you might have noticed, the selector syntax is almost identical to the WHERE clause in SQL, but the selector syntax uses message header and property names instead of database column names. Selector expressions can be as complex and expressive as you need them to be. They can include literals, identifiers, whitespace, expressions, stan- dard brackets, logical and comparison operators, arithmetic operators, and null com- parisons.
Common message selector types
| Type | Description | Example |
|---|---|---|
| Literals | Can be strings, exact or approximate numeric values, or Booleans. | BidManagerMDB 100 TRUE |
| Identifiers | Can be a message property or header name; case sensitive. | RECIPIENT NumOfBids Fragile JMSTimestamp |
| Whitespace | Same as defined in the Java language specification: space, tab, form feed, and line terminator. | |
| Comparison operators | Comparison operators, such as =, >, >=, <=, <>. | RECIPIENT='BidManagerMDB' NumOfBids>=100 |
| Logical operators | All three types of logical operators—NOT, AND, OR—are supported. | RECIPIENT='BidManagerMDB' AND NumOfBids>=100 |
| Null comparison | IS NULL and IS NOT NULL comparisons. | Firstname IS NOT NULL |
| True/false comparison | IS [NOT] TRUE and IS [NOT] FALSE comparisons. | Fragile is TRUE Fragile is FALSE |
Using bean lifecycle callbacks
- Creates MDB instances.
- Injects resources, including the message-driven context.
- Places instances in a managed pool (if the container supports pooling; if pool- ing isn’t supported, new instances are created when needed).
- Pulls an idle bean out of the pool when a message arrives (the container may have to increase the pool size at this point).
- Executes the message listener method—for example, the onMessage method.
- When the
onMessagemethod finishes executing, it pushes the idle bean back into the method-ready pool. - As needed, retires (and destroys) beans out of the pool.
Managing MDB transactions
By default, the container will start a transaction before the onMessage method is invoked and will commit the transaction when the method returns, unless the transac- tion was marked as rollback through the message-driven context or an unhandled runtime exception is thrown in the onMessage method.
You can specify this explicitly using the follow- ing code:
@MessageDriven
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class TurtleShippingRequestMessageBean
If you want, you can also tell the container that the MDB shouldn’t use transactions at all. In this case, you need to ensure database and message acknowledgment reliability yourself.
@MessageDriven
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class TurtleShippingRequestMessageBean
MDB best practices
- Choosing your messaging models carefully
- Don't overuse MDBs
- Remeber modularization
- An excellent practice is to put business logic in session beans and invoke them from the
onMessagemethod.
- An excellent practice is to put business logic in session beans and invoke them from the
- Make good use of message filters
- There are some valid reasons for using a single messaging destination for multiple purposes.
- You can then use message selectors on two sepa- rate MDBs to isolate and handle each kind of request.
- Choose message types carefully
- Be wary of poisoned messages
- The good news is that many MOMs and EJB containers provide mechanisms that deal with poisoned messages, including redelivery counts and dead-message queues.
- After the redelivery count is exceeded, the message will be moved to a specifically des- ignated queue for poisoned messages called the dead-message queue. The bad news is that these mechanisms aren’t standardized and are vendor-specific.
- Configure MDB pool size
- Consider nonpersistent messages, duplicate-OK acknowledgment, and nontransactional MDBs.