EJB 3 In Action - Woking with EJB components - MDB - Notes

159 阅读4分钟

Messaging concepts

Message-oriented middleware

image.png

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.

image.png

  • Publish-Subcribe

image.png

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.

image.png

JMS Message interface

image.png

  • Message Headers
    • JSMCorrelationID
    • JMSReplyTo
    • JMSMessageID
    • JMSTimestamp
  • 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

image.png

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 MessageListener interface through the XML deployment descriptor and leave this detail out of the code altogether:
<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 propertyDescription
destinationLookupThe JNDI lookup of a javax.jms.Queue or a javax.jms.Topic.
connectionFactoryLookupThe JNDI lookup of a javax.jms.ConnectionFactory, javax.jms.QueueConnectionFactory, or javax.jms.TopicConnectionFactory.
acknowledgeModeAuto-acknowledge (default) or Dups-ok-acknowledge.
messageSelectorA message select to filter the messages the MDB receives.
destinationTypejavax.jms.Queue or javax.jms.Topic.
subscriptionDurabilityApplies only to destinationType=avax.jms.Topic. Values are either Durable or NonDurable (default).
clientIdSets the client identifier used when connecting to the JMS provider.
subscriptionNameApplies 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 background
  • Dups-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
TypeDescriptionExample
LiteralsCan be strings, exact or approximate numeric values, or Booleans.BidManagerMDB 100 TRUE
IdentifiersCan be a message property or header name; case sensitive.RECIPIENT NumOfBids Fragile JMSTimestamp
WhitespaceSame as defined in the Java language specification: space, tab, form feed, and line terminator. 
Comparison operatorsComparison operators, such as =, >, >=, <=, <>.RECIPIENT='BidManagerMDB' NumOfBids>=100
Logical operatorsAll three types of logical operators—NOT, AND, OR—are supported.RECIPIENT='BidManagerMDB' AND NumOfBids>=100
Null comparisonIS NULL and IS NOT NULL comparisons.Firstname IS NOT NULL
True/false comparisonIS [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 onMessage method finishes executing, it pushes the idle bean back into the method-ready pool.
  • As needed, retires (and destroys) beans out of the pool.

image.png

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 onMessage method.
  • 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.