Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JMS Standalone consumer with ActiveMQ and Spring

Historically I've deployed my JMS consumer applications as Spring webapps deployed under Tomcat (Windows box). These consumers will then run alongside my other webapps under the same Tomcat instance. As the number of consumers that I use has grown, however, I've realized that this is turning into a bit of a maintenance nightmare.

My solution was to convert these webapps to "main method" standalone apps deployed as jars. In fact, I was able to successfully package them all together in an attempt to reuse as many resources (DAO, dependencies, etc) as possible.

Here's what my main method looks like:

public static void main(String[] args) {

    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

    try {
        FooListener fooListener = (FooListener) context.getBean("fooListener");

        fooListener.start();
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }

    try {
        BarListener barListener = (BarListener) context.getBean("barListener");

        barListener.start();
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }
}

My question(s):

  1. Do I need to do anything special to shut down my JMS connections in my main method application, or will they shut down just fine as the application terminates?
  2. Does anyone have any personal preferences or otherwise regarding whether to deploy jms consumers using tomcat or as standalone apps?

Edit:

A bit more information: FooListener and BarListener extend the following abstract class. They inherit their values from the corresponding beans in the applicationContext.xml file, and they both override the onMessage() method to asynchronously consume messages.

public abstract class TextMessageListener implements MessageListener {

    protected ConnectionFactory connectionFactory;

    protected String queueName;

    protected String selectors;

    public void start() throws JMSException {
        Connection connection = connectionFactory.createConnection();

        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);

        MessageConsumer consumer = session.createConsumer(session.createQueue(queueName), selectors);

        consumer.setMessageListener(this);

        connection.start();
    }

    public abstract void onMessage(Message message);
}
like image 887
Bryan Larson Avatar asked Oct 08 '22 14:10

Bryan Larson


1 Answers

You have to register a shutdown hook for your application context this way:

context.registerShutdownHook();

This will ensure that when the jvm is shutdown, the context is also closed gracefully.

My personal preference is always to deploy it to a container - even standalone apps like these, this is because of the following reasons:

  • The administration is easier - deploying/undeploying the application war, starting/stopping the container runtime.
  • If you need to build any kind of monitoring - how many messages are being consumed, this will be easier with this setup, you can just add web pages which present relevant information vs say using jmx with a standalone application.

Also, why are you explicitly calling the listener.start(), the Spring container does this automatically anyway?

like image 184
Biju Kunjummen Avatar answered Oct 12 '22 16:10

Biju Kunjummen