From 074a2123575267fd8df9887098f94a665e03a355 Mon Sep 17 00:00:00 2001 From: markpollack Date: Sat, 5 Jul 2008 11:14:19 +0000 Subject: [PATCH] msmq doc updates --- doc/reference/src/msmq.xml | 514 +++++++++++++++++++++++++------------ 1 file changed, 350 insertions(+), 164 deletions(-) diff --git a/doc/reference/src/msmq.xml b/doc/reference/src/msmq.xml index d39976f7..ec57464e 100644 --- a/doc/reference/src/msmq.xml +++ b/doc/reference/src/msmq.xml @@ -1,70 +1,109 @@ - + Message Oriented Middleware - MSMQ
Introduction The goals of Spring's MSMQ 3.0 messaging support is to raise the - level of abstraction when writing MSMQ applications. The System.Messaging - API is a low-level API that provides the basis for creating messaging an - application. 'Out-of-the-box', System.Messaging leaves the act of creating - a sophisticated mult-threaded messaging servers and clients as an + level of abstraction when writing MSMQ applications. The + System.Messaging API is a low-level API that provides + the basis for creating a messaging application. However, 'Out-of-the-box', + System.Messaging leaves the act of creating + sophisticated multi-threaded messaging servers and clients as an infrastructure activity for the developer. Spring fills this gap by proving easy to use helper classes that makes creating an enterprise messaging application easy. These helper classes take into account the - nuances of the System.Messaging API, such as its lack of thread-safety in - many cases, the handling of so-called 'poison messages' (messages that are - endlessly redelivered due to an unrecoverable exception during message - processing), and combining database transactions with message - transactions. Other goals of Spring's MSMQ messaging support are to - support messaging best practices, in particular encouraging a clean - architectural layering that separates the messaging middlware specifics - from the core business processing. + nuances of the System.Messaging API, such as its lack + of thread-safety in many cases, the handling of so-called 'poison + messages' (messages that are endlessly redelivered due to an unrecoverable + exception during message processing), and combining database transactions + with message transactions. Other goals of Spring's MSMQ messaging support + are to support messaging best practices, in particular encouraging a clean + architectural layering that separates the messaging middleware specifics + from the core business processing. Spring's approach to distributed computing has always been to - promote a plain old .NET object approach or a PONO proramming model. In + promote a plain old .NET object approach or a PONO programming model. In this approach plain .NET objects are those that are devoid of any reference to a particular middleware technology. Spring provides the 'adapter' classes that converts between the middleware world, in this case MSMQ, and the oo-world of your business processing. This is done through - the use of Spring's MessageListenerAdapter class and - IMessageConverters. + the use of Spring's MessageListenerAdapter class + and IMessageConverters. - The namespace Spring.Messaging provides the core functionality for - messaging. It contains the class MessageQueueTemplate that simplifies the - use of the the System.Messaging.MessageQueue by handling the lack of - thread-safety in most of System.Messaging.MessageQueue's methods (for - example Send). A single instance of MessageQueueTemplate can be used - througout your application and Spring will ensure that a different - instance of a MessageQueue class is used per thread. The - MessageQueueTemplate class is aware of the present of either an 'ambient' - System.Transaction's transaction or a local - System.Messaging.MessageQueueTransaction. As such you do not need to code - your messaing operations to a specific transaction enviornment or come up - with your own mechanism for passing around a MessageQueueTransaction to - multiple classes. The transaction features of MessageQueueTemplate are - quite analogous to the transactional features of Spring's AdoTemplate (in - case you are already familiar with that functionality). + The namespace Spring.Messaging provides the core + functionality for messaging. It contains the class + MessageQueueTemplate that simplifies the use of + System.Messaging.MessageQueue by handling the lack + of thread-safety in most of + System.Messaging.MessageQueue's methods (for example + Send). A single instance of + MessageQueueTemplate can be used throughout your + application and Spring will ensure that a different instance of a + MessageQueue class is used per thread when using + MessageQueueTemplate's methods. This per-thread + instance of a System.Messaging.MessageQueue is also + available via its property MessageQueue. The + MessageQueueTemplate class is also aware of the + presence of either an 'ambient' System.Transaction's + transaction or a local + System.Messaging.MessageQueueTransaction. As such + if you use MessageQueueTemplate's send and receive + methods, unlike with plain use of + System.Messaging.MessageQueue, you do not need to + keep track of this information yourself and call the correct overloaded + System.Messaging.MessageQueue method for a specific + transaction environment. When using a + System.Messaging.MessageQueueTransaction this would + usually require you as a developer to come up with your own mechanism for + passing around a MessageQueueTransaction to multiple + classes and layers in your application. + MessageQueueTemplate manages this for you, so you don't + have to do so yourself. These resource management and transaction features + of MessageQueueTemplate are quite analogous to the + transactional features of Spring's AdoTemplate in case + you are already familiar with that functionality. - For asynchronous reception Spring provides several multie-threaded + For asynchronous reception Spring provides several multi-threaded message listener containers. You can pick and configure the container that matches your message transactional processing needs and configure - poison-message handling policies. + poison-message handling policies. The message listener container leverages + Spring's support for managing transactions. Both DTC, local messaging + transactions, and local database transactions are supported. In + particular, you can easily coordinating the commit and rollback of a local + MessageQueueTransaction and a local database transaction when they are + used together. + + From a programming perspective, Spring's MSMQ support involves you + configuring message listener containers and + writing a callback function for message processing. + On the sending side, it involves you learning how to use + MessageQueueTemplate. In both cases you will quite + likely want to take advantage of using + MessageListenerConverters so you can better + structure the translation from the System.Messaging.Message data structure + to your business objects. After the initial learning hurdle, you should + find that you will be much more productive leveraging Spring's helper + classes to write enterprise MSMQ applications than rolling your own + infrastructure. Feedback and new feature requests are always + welcome.
A quick tour for the impatient Here is a quick example of how to use Spring's MSMQ support to - create a simple client that sends a message and a multi-threaded server - application that receives the message. + create a client that sends a message and a multi-threaded server + application that receives the message. (The client code could also be used + as-is in a multi-threaded environment but this is not + demonstrated). On the client side you create an instance of the - MessageQueueTemplate class and configure it to use a MessageQueue. This - can be done programmatically but it is common to use dependency injection - and Spring's XML configuration file to configure your client class as - shown below. + MessageQueueTemplate class and configure it to use + a MessageQueue. This can be done programmatically + but it is common to use dependency injection and Spring's XML + configuration file to configure your client class as shown below. <object id='questionTxQueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'> <property name='Path' value='.\Private$\questionTxQueue'/> @@ -82,10 +121,11 @@ - The MessageQueue object is created via an instance of - MessageQueueFactoryObject and the MessageQueueTemplate refers to this - factory object by name and not by reference. The SimpleSender class looks - like this + The MessageQueue object is created via an + instance of MessageQueueFactoryObject and the + MessageQueueTemplate refers to this factory object + by name and not by reference. The SimpleSender + class looks like this public class QuestionService : IQuestionService { @@ -103,53 +143,71 @@ } This class can be shared across multiple threads and the - MessageQueueTemplate will take care of managing thread local access to - System.Messaging.MessageQueue and underlying - System.Messaging.IMessageFormatter instances appropriately. Futhermore, - since this is a transactional queue (only the name gives it away), the - message will be sent using a single local messaging transaction. The - conversion from the string to the underling message is managed by an - instance of the IMessageConverter class. By default an implementation that - uses an XmlMessageFormatter with a TargetType of System.String is used. - You can configure the MessageQueueTemplate to use other implementations - that do conversions above and beyond what the 'stock' IMessageFormatters - do. See the section on MessageConverters for more details. + MessageQueueTemplate will take care of managing + thread local access to a + System.Messaging.MessageQueue as well as any + System.Messaging.IMessageFormatter instances. + + + Furthermore, since this is a transactional queue (only the name + gives it away), the message will be sent using a single local messaging + transaction. The conversion from the string to the underling message is + managed by an instance of the IMessageConverter + class. By default an implementation that uses an + XmlMessageFormatter with a + TargetType of System.String is + used. You can configure the MessageQueueTemplate to use + other IMessageConveter implementations that do + conversions above and beyond what the 'stock' + IMessageFormatters do. See the section on + MessageConverters for more details. On the receiving side we would like to consume the messages transactionally from the queue. Since no other database operations are being performed in our server side processing, we select the - TransactionMessageListenerContainer and configure it to use the - MessageQueueTransactionManager (an implementation of Spring's - IPlatformTransactionManager abstraction). The configuration is shown + TransactionMessageListenerContainer and configure + it to use the MessageQueueTransactionManager. The + MessageQueueTransactionManager an implementation of + Spring's IPlatformTransactionManager abstraction + that provides a uniform API on top of various transaction manager + (ADO.NET,NHibernate, MSMQ, etc). + + While you can create the message listener container + programmatically, we will show the declarative configuration approach below - <object id='questionTxQueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'> + <!-- Queue to receive from --> + <object id='questionTxQueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'> <property name='Path' value='.\Private$\questionTxQueue'/> <property name='MessageReadPropertyFilterSetAll' value='true'/> </object> + <!-- MSMQ Transaction Manager --> <object id="messageQueueTransactionManager" type="Spring.Messaging.Core.MessageQueueTransactionManager, Spring.Messaging"/> + <!-- Message Listener Container that uses MSMQ transactional for receives --> <object id="transactionalMessageListenerContainer" type="Spring.Messaging.Listener.TransactionalMessageListenerContainer, Spring.Messaging"> <property name="MessageQueueObjectName" value="questionTxQueue"/> <property name="PlatformTransactionManager" ref="messageQueueTransactionManager"/> <property name="MaxConcurrentListeners" value="10"/> <property name="MessageListener" ref="messageListenerAdapter"/> </object> - + + <!-- Adapter to call a PONO as a messaging callback --> <object id="messageListenerAdapter" type="Spring.Messaging.Listener.MessageListenerAdapter, Spring.Messaging"> <property name="HandlerObject" ref="questionHandler"/> </object> - <!-- Class that you write --> + <!-- The PONO class that you write --> <object id="questionHandler" type="MyNamespace.QuestionHandler, MyAssembly"/> We have specified the queue to listen, that we want to consume the messages transactionally, process messages from the queue using 10 threads, and that our plain object that will handle the business - processing is of the type QuestionHandler. The only class you need to - write, QuestionHandler, looks like + processing is of the type QuestionHandler. The only + class you need to write, QuestionHandler, looks + like public class QuestionHandler : IQuestionHandler { @@ -170,30 +228,51 @@ does not refer to any messaging specific class. The rest is configuration of Spring provided helper classes. - Note that if the HandleObject method has returned a string value a - reply message would be sent to a response queue. The response queue would - be taken from the Message's own ResponseQueue property - or can be specified explicitly using MessageListenerAdapter's - DefaultResponseQueueName property. + Note that if the HandleObject method has returned + a string value a reply message would be sent to a response queue. The + response queue would be taken from the Message's own + ResponseQueue property or can be specified explicitly + using MessageListenerAdapter's DefaultResponseQueueName + property. - As a last part of this 'quick tour' we will configure the message + If an exception is thrown inside the QuestionHandler, then the MSMQ + transaction is rolled back, putting the message back on the queue for + redelivery. If the exception is not due to a transient error in the + system, but a logical processing exception, then one would get endless + redelivery of the message - clearly not a desirable situation. These + messages are so called 'poison messages' and a strategy needs to be + developed to deal with them. This is left as a development task if you + when using the System.Messaging APIs but Spring provides a strategy for + handling poison messages, both for DTC based message reception as well as + for local messaging transactions. + + In the last part this 'quick tour' we will configure the message listener container to handle poison messages. This is done by creating an instance of SendToQueueExceptionHandler and setting - the MaxRetry count and the queue to send the message to - should that retry count be exeeded. + the property MaxRetry to be the number of exceptions or + retry attempts we are willing to tolerate before taking corrective + actions. In this case, the corrective action is to send the message to + another queue. We can then create other message listener containers to + read from those queues and handle the messages appropriately or perhaps + you will avoid automated processing of these messages and take manual + corrective actions. - <object id='retryQuestionTxQueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'> + + <!-- The 'retry' queue to send poison messages --> + <object id='retryQuestionTxQueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'> <property name='Path' value='.\Private$\retryQuestionTxQueue'/> <property name='MessageReadPropertyFilterSetAll' value='true'/> </object> + <!-- Message Listener Container that uses MSMQ transactional for receives --> <object id="transactionalMessageListenerContainer" type="Spring.Messaging.Listener.TransactionalMessageListenerContainer, Spring.Messaging"> - <!-- as before but adding --> - + <!-- as before but adding --> + <property name="MessageTransactionExceptionHandler" ref="messageTransactionExceptionHandler"/> </object> + <!-- Poison message handling policy --> <object id="messageTransactionExceptionHandler" type="Spring.Messaging.Listener.SendToQueueExceptionHandler, Spring.Messaging"> <property name="MaxRetry" value="5"/> <property name="MessageQueueObjectName" value="retryQuestionTxQueue"/> @@ -204,9 +283,17 @@ queue questionTxQueue for redelivery). If the same message causes an exception in processing 5 times ,then it will be sent transactionally to the retryQuestionTxQueue and the message transaction will commit (removing - it from the queue questionTxQueue). + it from the queue questionTxQueue). The SendToQueueExceptionHandler + implements the interface + IMessageTransactionExceptionHandler (discussed + below) so you can write your own implementations should the provided ones + not meet your needs. - + That's the quick tour folks. Hopefully you got a general feel for + how things work, what requires configuration, and what is the code you + need to write. The following sections describe each of Spring's helper + classes in more detail. The sample application that ships with Spring is + also a good place to get started.
@@ -219,23 +306,30 @@ synchronously sending and receiving messages. A single instance can be shared across multiple threads, unlike the standard System.Messaging.MessageQueue class. (One less - resource managment issue to worry about!) A thread-local instance of the - MessageQueue class is available via + resource management issue to worry about!) A thread-local instance of + the MessageQueue class is available via MessageQueueTemplate's property - MessageQueue. + MessageQueue. A + MessageQueueTemplate is created by passing a + reference to the name of a + MessageQueueFactoryObject, you can think of it as + a friendly name for your MessagingQueue and the + recipe of how to create an instance of it. See the following section on + MessageQueueFactoryObject for more + information. The MessageQueueTemplate also provides several - convenience methods for sending and recieving messages. A family of + convenience methods for sending and receiving messages. A family of overloaded ConvertAndSend and ReceiveAndConvert methods allow you to send and - recieve an object. The default message queue to send and recieve from is + receive an object. The default message queue to send and receive from is specified using the MessageQueueTemplate's property MessageQueueObjectName. The responsibility of converting the object to a Message and vice versa is - the responsibility of the template's associated - IMessageConverter implementation. This can be set - using the property MessageConverter. The default - implementation, XmlMessageConverter, uses an + given to the template's associated IMessageConverter + implementation. This can be set using the property + MessageConverter. The default implementation, + XmlMessageConverter, uses an XmlMessageFormatter with its TargetType set to System.String. Note that @@ -243,10 +337,12 @@ also not thread safe, so MessageQueueTemplate ensures that thread-local instances of IMessageConverter are used (as they generally - wrap IMessageFormatter's) + wrap IMessageFormatter's that are not + thread-safe). You can use the MessageQueueTemplate to send - messages to other MessageQueues by specifying their queue name. + messages to other MessageQueues by specifying their queue 'object name', + the name of the MessageQueueFactoryObject. The family of overloaded ConvertAndSend and ReceiveAndConvert methods are shown below @@ -271,11 +367,12 @@ object ReceiveAndConvert(string messageQueueObjectName); (put there via the use of Spring's MessageQueueTransactionManager or TransactionalMessageListenerContainer), the - message will be sent transactionally using the transaction object in - thread local storage. This lets you group together multiple messaging - operations within the same transaction without having to explicitly pass - around the MessageQueueTransaction object. If the - message queue is transactional but there is no ambient + message will be sent transactionally using the + MessageQueueTransaction object in thread local + storage. This lets you group together multiple messaging operations + within the same transaction without having to explicitly pass around the + MessageQueueTransaction object. If the message + queue is transactional but there is no ambient MessageQueueTransaction, then a single message transaction is created on each messaging operation. (MessageQueueTransactionType = Single). If there is an ambient @@ -284,8 +381,8 @@ object ReceiveAndConvert(string messageQueueObjectName); transactional, then a non-transactional send (MessageQueueTransactionType = None) is used. - The delegate MessagePostProcessorDelegate has the following - signature + The delegate MessagePostProcessorDelegate + has the following signature public delegate Message MessagePostProcessorDelegate(Message message); @@ -295,7 +392,7 @@ object ReceiveAndConvert(string messageQueueObjectName); useful for setting Message properties (e.g. CorrelationId, AppSpecific, TimeToReachQueue). Using anonymous delegates in .NET - 2.0 makes this a very suscint coding task. If you have elaborate + 2.0 makes this a very succinct coding task. If you have elaborate properties that need to be set, perhaps creating a custom IMessageConverter would be appropriate. @@ -315,18 +412,73 @@ void Send(MessageQueue messageQueue, Message message); Note that in the last Send method that takes a MessageQueue instance, it is the callers - responsibility to ensure that this instance is not access from multipe - threads. This Send method is commonly used when - getting the MessageQueue from the + responsibility to ensure that this instance is not accessed from + multiple threads. This Send method is commonly used + when getting the MessageQueue from the ResponseQueue property of a - Message. The recieve timeout of the - Receive operations is set using the - ReceiveTimeout property of + Message during an asynchronous receive process. + The receive timeout of the Receive operations is set + using the ReceiveTimeout property of MessageQueueTemplate. The default value is MessageQueue.InfiniteTimeout (which is actually ~3 months).
+
+ MessageQueueFactoryObject + + The MessageQueueFactoryObject is + responsible for creating MessageQueue instances. + You configure the factory with some basic information, namely the + constructor parameters you are familiar with already when creating a + standard MessageQueue instance, and then setting + MessageQueue properties, such a Label etc. Some + configuration tasks of a MessageQueue involve + calling methods, for example to set which properties of the message to + read. These available as properties to set on the + MessageQueueFactoryObject. An example declarative + configuration is shown below + + <object id='testqueue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'> + <!-- propeties passed to the MessageQueue constructor --> + <property name='Path' value='.\Private$\testqueue'/> + <property name='DenySharedReceive' value='true'/> + <property name='AccessMode' value='Receive'/> + <property name='EnableCache' value='true'/> + <!-- properties that call configuration methods on the MessageQueue --> + <property name='MessageReadPropertyFilterSetAll' value='true'/> + <property name='ProductTemplate'> + <object> + <property name='Label' value='MyLabel'/> + <!-- other MessageQueue properties can be set here --> + </object> + </property> + </object> + + Whenever an object reference is made to 'testqueue' an new + instance of the MessageQueue class is created. + This Spring's so-called 'prototype' model, which differs from + 'singleton' mode. In the singleton creation mode whenever an object + reference is made to a 'testqueue' the same + MessageQueue instance would be used. So that a + new instance can be retrieved based on need, the message listener + containers take as an argument the name of the + MessageQueueFactoryObject and not a reference. + (i.e. use of 'value' instead of 'ref' in the XML). + + + The MessageQueueFactoryObject class is an + ideal candidate for use of a custom namespace. This will be provided + in the future. This will allow you to use VS.NET IntelliSense to + configure this commonly used object. An example of the potential + syntax is shown below + + <mq:messageQueue id="testqueue" path=".\Private$\testqueue" MessageReadPropertyFilterSetAll="true"> + <mq:properties label="MyLabel"/> +</mq:messageQueue> + +
+
MessageQueue and IMessageConverter resource management @@ -341,19 +493,38 @@ void Send(MessageQueue messageQueue, Message message); Receive. To isolate the creation logic of these classes, the factory - interface IMessageQueueFactory is used. A - provided implementation, + interface IMessageQueueFactory is used. The + interface is shown below + + public interface IMessageQueueFactory + { + MessageQueue CreateMessageQueue(string messageQueueObjectName); + + IMessageConverter CreateMessageConverter(string messageConverterObjectName); + } + + A provided implementation, DefaultMessageQueueFactory will create an - instance of each class per-thread. This leverages Spring's local thread - storage support so it will work correctly in stand alone and web - applications. You can use the - DefaultMessageQueueFactory independent of the - rest of Sprng's MSMQ support should you need only this functionality. - MessageQueueTemplate and the listener containers - create this implementation by default, but should you want to share the - same instance across these two classes, or provide your own custom - implementation, use the property - MessageQueueFactory. + instance of each class per-thread. It delegates the creation of the + MessageQueue instance to the Spring container. + The argument, messageConverterObjectName, must be the id/name of a + MessageQueueFactoryObject defined in the Spring + container. + + DefaultMessageQueueFactory leverages + Spring's local thread storage support so it will work correctly in stand + alone and web applications. + + You can use the DefaultMessageQueueFactory + independent of the rest of Spring's MSMQ support should you need only + the functionality it offers. MessageQueueTemplate + and the listener containers create an instance of + DefaultMessageQueueFactory by default. Should you + want to share the same instance across these two classes, or provide + your own custom implementation, use the property + MessageQueueFactory on either + MessageQueueTemplate or the message listener + classe.s
@@ -363,13 +534,15 @@ void Send(MessageQueue messageQueue, Message message); messages delivered asynchronously. This support is provided in Spring by message listener containers. A message listener container is the intermediary between an IMessageListener and a - MessageQueue. It takes care of registering to - receive messages, participating in transactions, resource acquisition - and release, exception conversion and suchlike. This allows you as an - application developer to write the (posssibly complex) business logic - associated with receiving a message (and possibly responding to it), and - delegates boilerplate MSMQ infrastructure concerns to the framework. - + MessageQueue. (Note, message listener containers + are conceptually different than Spring's Inversion of Control container, + though it integrates and leverages the IoC container.) The message + listener container takes care of registering to receive messages, + participating in transactions, resource acquisition and release, + exception conversion and suchlike. This allows you as an application + developer to write the (possibly complex) business logic associated with + receiving a message (and possibly responding to it), and delegate + boilerplate MSMQ infrastructure concerns to the framework. A subclass of AbstractMessageListenerContainer is used to @@ -386,13 +559,13 @@ void Send(MessageQueue messageQueue, Message message); TransactionalMessageListenerContainer - - surrounds the receive operation with a local (non-DTC) based - transaction + surrounds the receive operation with local (non-DTC) based + transaction(s). DistributedTxMessageListenerContainer - - surrounds the receive operation with a distribued (DTC) + surrounds the receive operation with a distributed (DTC) transaction @@ -404,13 +577,13 @@ void Send(MessageQueue messageQueue, Message message); transactions, either local MSMQ transactions, local ADO.NET based transactions, or DTC transactions. Each container can specify the number of threads that will be created for processing messages after the Peek - occurs.via the property MaxConcurrentListeners. Each - processing thread will continue to listen for messages up until the the + occurs via the property MaxConcurrentListeners. Each + processing thread will continue to listen for messages up until the timeout value specified by ListenerTimeLimit or until there are no more messages on the queue (whichever comes first). The default value of ListenerTimeLimit is TimeSpan.Zero, meaning that only one attempt to - recieve a message from the queue will be performed by each listener + receive a message from the queue will be performed by each listener thread. The current implementation uses the standard .NET thread pool. Future implementations will use a custom (and pluggable) thread pool. @@ -418,13 +591,14 @@ void Send(MessageQueue messageQueue, Message message);
NonTransactionalMessageListenerContainer - This container performs a Recieve operation on the MessageQueue - without any transactional settings. As such messages will not be - redelivered if an exception is thrown during message processing. - Exceptions during message processing can be handled via an - implementation of the interface IExceptionHandler. This can be set via - the property ExceptionHandler on the listener. The IExceptionHandler - interface is shown below + This container performs a Recieve operation on the + MessageQueue without any transactional + settings. As such messages will not be redelivered if an exception is + thrown during message processing. Exceptions during message processing + can be handled via an implementation of the interface + IExceptionHandler. This can be set via the + property ExceptionHandler on the listener. The + IExceptionHandler interface is shown below public interface IExceptionHandler { @@ -432,8 +606,8 @@ void Send(MessageQueue messageQueue, Message message); } An example of configuring a - NonTransactionalMessageListenerContainer with an IExceptionHandler is - shown below + NonTransactionalMessageListenerContainer with + an IExceptionHandler is shown below <!-- Queue to receive from --> @@ -479,33 +653,44 @@ void Send(MessageQueue messageQueue, Message message); <object id="exceptionHandler" type="MyNamespace.SimpleExceptionHandler, MyAssembly"/> + + The SimpleHandler class would look something like this + + public class SimpleHandler : ISimpleHandler +{ + public void HandleObject(string txt) + { + // perform message processing... + Console.WriteLine("Received text: " + txt); + } +}
TransactionalMessageListenerContainer - This message listener container peforms receive operations + This message listener container performs receive operations within the context of local transaction. This class requires an instance of Spring's IPlatformTransactionManager, either AdoPlatformTransactionManager, HibernateTransactionManager, or - MessageQueueTransactionManager. + MessageQueueTransactionManager. If you specify a MessageQueueTransactionManager then a MessageQueueTransaction will be started before - receiving the message and used as part of the container's recieve + receiving the message and used as part of the container's receive operation. As with other IPlatformTransactionManager implementation's, the transactional resources (in this case an instance of the MessageQueueTransaction class) is bound to thread local storage. MessageQueueTemplate will look in thread-local storage and use this 'ambient' transaction if - found for its send and recieve operations. The message listener is + found for its send and receive operations. The message listener is invoked and if no exception occurs, then the MessageQueueTransactionManager will commit the - MessageQueueTransaction. + MessageQueueTransaction. The message listener implementation can call into service layer classes that are made transactional using standard Spring declarative @@ -521,7 +706,7 @@ void Send(MessageQueue messageQueue, Message message); a MessageQueueTransactionManager is a powerful combination that can be used to achieve "exactly one" transaction message processing with database operations. This - requires a little extra programming effort and is a more efficinet + requires a little extra programming effort and is a more efficient alternative than using distributed transactions which are commonly associated with this functionality since both the database and the message transaction commit or rollback together. @@ -534,7 +719,7 @@ void Send(MessageQueue messageQueue, Message message); commit, resulting in message redelivery. The transactional service layer needs logic to detect if incoming message was processed successfully. It can do this by checking the database for an - indication of successfull processing, perhaps by recording the + indication of successful processing, perhaps by recording the Message.Id itself in a status table. If the transactional service layer determines that the message has already been processed, it can throw a specific exception for this @@ -623,7 +808,7 @@ void Send(MessageQueue messageQueue, Message message); false. In case of exceptions during IMessageListener - processing when using either ither + processing when using either either AdoPlatformTransactionManager or HibernateTransactionManager the container's IMessageTransactionExceptionHandler will @@ -634,7 +819,7 @@ void Send(MessageQueue messageQueue, Message message); Poison message handing, that is, the endless redelivery of a message due to exceptions during processing, can be detected using - implementatons of the + implementations of the IMessageTransactionExceptionHandler. This interface is shown below @@ -653,9 +838,9 @@ void Send(MessageQueue messageQueue, Message message); The IMessageTransactionExceptionHandler implementation SendToQueueExceptionHandler keeps track of the Message's Id property in memory - with a count of how many times an exception has occured. if that count - is greater than the handler's MaxRetry count it - will be sent to another queue using the provided + with a count of how many times an exception has occurred. If that + count is greater than the handler's MaxRetry count + it will be sent to another queue using the provided MessageQueueTransaction. The queue to send the message to is specified via the property MessageQueueObjectName. @@ -664,15 +849,15 @@ void Send(MessageQueue messageQueue, Message message);
DistributedTxMessageListenerContainer - This message listener container peforms receive operations + This message listener container performs receive operations within the context of distributed transaction. A distributed - transaction is started before a message is recieved. The recieve + transaction is started before a message is received. The receive operation participates in this transaction using by specifying MessageQueueTransactionType = Automatic. The transaction that is started is automatically promoted to two-phase-commit to avoid the default behavior of transaction promotion since the only reason to use this container is to use two different resource managers (messaging - and database typically). + and database typically). The commit and rollback semantics are simple, if the message listener does not throw an exception the transaction is committed, @@ -696,15 +881,15 @@ void Send(MessageQueue messageQueue, Message message); the incoming message is a poison message. This method is called before the IMessageListener is invoked. The container will call HandlePoisonMessage is - IsPoisonMessage returns true.and will then commit - the distibuted transaction (removing the message from the queue. + IsPoisonMessage returns true and will then commit + the distributed transaction (removing the message from the queue. Typical implementations of HandlePoisonMessage will move the poison message to another queue (under the same distributed transaction used to receive the message). The class SendToQueueDistributedTransactionExceptionHandler detects poison messages by tracking the Message Id property in memory with a count of how many times an exception has - occured. if that count is greater than the handler's + occurred. If that count is greater than the handler's MaxRetry count it will be sent to another queue. The queue to send the message to is specified via the property MessageQueueObjectName. @@ -735,7 +920,8 @@ void Send(MessageQueue messageQueue, Message message); } There are a standard implementations provided the simply wrap - existing IMessageFormatter implementations. + existing IMessageFormatter + implementations. @@ -763,15 +949,15 @@ void Send(MessageQueue messageQueue, Message message); - XmlDocumentConverter - loads and saves an XmlDocument to the - messgae BodyStream. This lets you manipulate direclty the XML data - independent of type serialization issues. This is quite useful if - you use XPath expressions to pick out the relevant information to - construct your business objects. + XmlDocumentConverter - loads and saves + an XmlDocument to the messgae BodyStream. This lets you manipulate + directly the XML data independent of type serialization issues. This + is quite useful if you use XPath expressions to pick out the + relevant information to construct your business objects. - Other potential implementationsRaw + Other potential implementations: @@ -807,9 +993,9 @@ void Send(MessageQueue messageQueue, Message message); of a class that does not implement the IMessageListener interface to be invoked upon message delivery. Lets call this class the 'message handler' class. To - achive this goal the MessageListenerAdapter + achieve this goal the MessageListenerAdapter implements the standard IMessageListener - interface to recieve a message and then delegates the processing to + interface to receive a message and then delegates the processing to the message handler class. Since the message handler class does not contain methods that refer to MSMQ artifacts such as Message, the MessageListenerAdapter uses a @@ -846,7 +1032,7 @@ void Send(MessageQueue messageQueue, Message message); } If your IMessageConverter implementation will return multiple - object types, overloading the handler method is perfectly acceptible, + object types, overloading the handler method is perfectly acceptable, the most specific matching method will be used. A method with an object signature would be consider a 'catch-all' method of last resort. @@ -905,9 +1091,9 @@ void Send(MessageQueue messageQueue, Message message); those of WCF with its MSMQ related bindings, in as much as a WCF service contract is a PONO (minus the attributes if you really picky about what you call a PONO). Spring's messaging support can give you the programming - conveninece of dealing with PONO contracts for message receiving but does + convenience of dealing with PONO contracts for message receiving but does not (at the moment) provide a similar PONO contract for sending, instead - relying on explict use of the MessageQueueTemplate class. This feature + relying on explicit use of the MessageQueueTemplate class. This feature exists - some question whether it should for messaging - in the Java version of the Spring framework, see JmsInvokerServiceExporter and JmsInvokerProxyFactoryBean.