The connection factory and JMS template have most of their specific configuration parameters externalized to facilitate better reuse.
For the ActiveMQ connection factory, the externalized properties include the broker URL, use of asynchronous sends and choice around dispatching asynchronously. The example XML template that follows includes some commentary around the pros/cons of configuring the last two. This factory is used by Spring's caching connection factory, externalizes configuration of session cache size, and assumes the presence of an exception listener.
The JMS template has the following properties that are configurable: delivery mode, time-to-live, whether or not explicit quality of service is enabled, whether or not the session is transacted, whether or not a given connection should listen for messages sent by that same connection, and whether or not the domain is pub-sub or point-to-point.
I would have externalized configuration for the listener container but, as it turns out, apparently the listener-container parent tag does not support this, so I've hardwired this to use the default listener container, listening on a topic within a transaction.
Here's that template:
<?xml version="1.0" encoding="UTF-8"?> <!-- A reusable template for Spring-JMS applications. The following must be configured externally, presumably via Spring's property-placeholder mechanism: brokerURL useAsyncSend dispatchAsync sessionCacheSize deliveryMode explicitQosEnabled sessionTransacted pubSubNoLocal pubSubDomain destination As well, the following is assumed: An exception listener that can be dereference by the name 'myExceptionListener' is assumed present in classpath. A message listener that can be dereference by the name 'myListener' is assumed present in classpath. --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:jms="http://www.springframework.org/schema/jms" xmlns:amq="http://activemq.apache.org/schema/core" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.3.0.xsd http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd"> <!-- Configure connection factory --> <bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> <!-- for testing, we want to use vm://localhost?async=false&broker.persistent=false. This does intra-JVM messaging using synchronous sends and doesn't bother with persisting messages to cover provider failures. See http://activemq.apache.org/uri-protocols.html for protocol options. --> <property name="brokerURL" value="${testUrl}"/> <!-- See http://activemq.apache.org/async-sends.html - use async sends for better throughput but only if you're able to tolerate some message loss. From the FUSE Tuning Guide (http://fusesource.com/wiki/display/ProdInfo/FUSE%20Message%20Broker%20Performance%20Tuning%20Guide): If you are using persistent messaging and you don't want to use Async Sends (see below) then you should use JMS transactions to batch up many operations inside a single transaction. If you enable Async Sends then you will reduce the blocking in senders which increases throughput. The only downside of asynchronous sending is if the send fails for whatever reason (security exception typically or some transport failure), then you don't get an exception thrown in the sender thread, since all the work is done asynchronously, though your ErrorListener will get notified. From the activemq.xsd: Forces the use of Async Sends which adds a massive performance boost; but means that the send() method will return immediately whether the message has been sent or not which could lead to message loss. --> <property name="useAsyncSend" value="${useAsyncSend}"/> <!-- From the activemq.xsd: Enables or disables the default setting of whether or not consumers have their messages dispatched synchronously or asynchronously by the broker. For non-durable topics for example we typically dispatch synchronously by default to minimize context switches which boost performance. However sometimes its better to go slower to ensure that a single blocked consumer socket does not block delivery to other consumers. See http://activemq.apache.org/consumer-dispatch-async.html. --> <property name="dispatchAsync" value="${dispatchAsync}"/> </bean> <!-- Use the vanilla connection factory to configure a caching connection factory, using the Spring version instead of ActiveMQ. Default session cache size for Spring factory is 1. An exception listener that can be dereference by the name 'myExceptionListener' is assumed present in classpath. --> <bean id="cachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory" destroy-method="destroy"> <property name="targetConnectionFactory" ref="connectionFactory"/> <property name="sessionCacheSize" value="${sessionCacheSize}"/> <property name="exceptionListener" ref="myExceptionListener"/> </bean> <!-- The JMS template intended for sending of messages. --> <bean id="myTemplate" class="org.springframework.jms.core.JmsTemplate"> <constructor-arg ref="cachingConnectionFactory"/> <property name="deliveryMode" value="${deliveryMode}"/> <property name="timeToLive" value="${timeToLive}"/> <!-- if explicit QoS is enabled, you can control deliveryMode, priority and TTL on a per-send basis --> <property name="explicitQosEnabled" value="${explicitQosEnabled}"/> <property name="sessionTransacted" value="${sessionTransacted}"/> <property name="pubSubNoLocal" value="${pubSubNoLocal}"/> <!-- override JMS template default domain type of PTP if you want pub-sub --> <property name="pubSubDomain" value="${pubSubDomain}"/> </bean> <!-- concurrency should be 1 for topic listeners. This is one attribute that apparently canNOT be externalized into the properties file. Use transacted acknowledgment (another attribute that cannot be externalized). A message listener that can be dereference by the name 'myListener' is assumed present in classpath. --> <jms:listener-container container-type="default" destination-type="topic" acknowledge="transacted" connection-factory="cachingConnectionFactory" concurrency="1"> <jms:listener destination="${myTopic}" ref="myListener"/> </jms:listener-container> </beans>
That's a starting point; from here, I'll add configuration, listeners and a test case as the next step.
References
Apache ActiveMQ
Spring 3.0.0 Javadoc
ActiveMQ Javadoc
FUSE Tuning Guide
Spring 3.0.0 Reference Documentation
Efficient Lightweight JMS with Spring and ActiveMQ
Creating Robust JMS Applications (Java EE 5 Tutorial)
No comments:
Post a Comment