This example shows you how to configure ActiveMQ so messages are expipired after a certain time..
Messages can be retained in the messaging system for a limited period of time before being removed. JMS specification states that clients should not receive messages that have been expired (but it does not guarantee this will not happen).
ActiveMQ can assign a expiry address to a given queue so that when messages are expired, they are removed from the queue and routed to an this address. These "expired" messages can later be consumed for further inspection.
The example will send 1 message with a short time-to-live to a queue. We will wait for the message to expire and checks that the message is no longer in the queue it was sent to. We will instead consume it from an expiry queue where it was moved when it expired.
Expiry destinations are defined in the configuration file activemq-configuration.xml:
<address-setting match="jms.queue.exampleQueue">
<expiry-address>jms.queue.expiryQueue</expiry-address>
</address-setting>
This configuration will moved expired messages from the exampleQueue
to the expiryQueue
ActiveMQ allows to specify either a Queue
by prefixing the expiry-address
with jms.queue.
or a Topic
by prefixing with jms.topic.
.
In this example, we will use a Queue
to hold the expired messages.
Since we want to consume messages from this expiryQueue, we also need to add a JNDI binding to perform a lookup. This is configured in activemq-jms.xml
<queue name="expiryQueue">
<entry name="/queue/expiryQueue"/>
</queue>
To run the example, simply type mvn verify -Pexample
from this directory
client-jndi.properties
file in the directory ../common/config
InitialContext initialContext = getContext();
Queue queue = (Queue) initialContext.lookup("/queue/exampleQueue");
ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("/ConnectionFactory");
connection = cf.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session.createProducer(topic);
producer.setTimeToLive(1000);
TextMessage message = session.createTextMessage("this is a text message");
producer.send(message);
Thread.sleep(5000);
We will now try to consume the message from the queue but it won't be there since it has expired
MessageConsumer messageConsumer = session.createConsumer(queue);
connection.start();
messageReceived
will be null
TextMessage messageReceived = (TextMessage) messageConsumer.receive(5000);
System.out.println("Received message from " + queue.getQueueName() + ": " + messageReceived);
However, we have configured ActiveMQ to send any expired messages to the expiryQueue
.
We will now consume messages from this expiry queue and receives the expired message.
Queue expiryQueue = (Queue)initialContext.lookup("/queue/expiryQueue");
MessageConsumer expiryConsumer = session.createConsumer(expiryQueue);
messageReceived = (TextMessage)expiryConsumer.receive(5000);
System.out.println("Received message from " + expiryQueue.getQueueName() + ": " + messageReceived.getText());
JMS does not specify the notion of expiry queue. From JMS point of view, the message received from the expiry queue
is a different message than the message expired from the queue: the two messages have the same content (properties and body) but
their JMS headers differ.
ActiveMQ defines additional properties to correlate the message received from the expiry queue with the
message expired from the queue
System.out.println("Destination of the expired message: " + ((Queue)messageReceived.getJMSDestination()).getQueueName());
System.out.println("Expiration time of the expired message (relative to the expiry queue): " + messageReceived.getJMSExpiration());
As we have not defined a time-to-live for the expiry queue, messages sent to the expiry queue will be kept forever (their JMS Expiration value is 0)
_HORNETQ_ORIG_DESTINATION
property
System.out.println("*Origin destination* of the expired message: " + messageReceived.getStringProperty("_HORNETQ_ORIG_DESTINATION"));
_HORNETQ_ACTUAL_EXPIRY
property
System.out.println("*Actual expiration time* of the expired message: " + messageReceived.getLongProperty("_HORNETQ_ACTUAL_EXPIRY"));
finally
block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects
finally
{
if (initialContext != null)
{
initialContext.close();
}
if (connection != null)
{
connection.close();
}
}