Pages

Wednesday, September 21, 2011

Solution for: Spring JMS + ActiveMQ + Tomcat = Tomcat does not shutdown

This is one of the most frustrating problems. When you decide to use Tomcat with Spring JMS to connect and message with ActiveMQ, everything works fine till you try to shutdown Tomcat.  It keeps throwing exception and looks like the DefaultMessageListnerContainer thread lives on. As seen from the logs on tomcat console, the problem occurs because the tomcat shutsdown before the JMS Spring container “DefaultMessageListenerContainer” and you will see Nullpointer, Classnotfound exceptions, as tomcat container is down and the classloader doesn’t exist to give the necessary classes from the previously loaded jars. And I could not find a single solution on google. After, much googling I found a solution for a similar problem when using Quartz, tomcat and spring. So, this solution was derived from that one [Sorry, I don’t have that link anymore].

Create a ServletContextListener, and in contextDestroyed method get the jms container bean to manually call shutdown. The listener contextInitialized and contextDestroyed are called at start and end of Servlet lifecycle. The below code assumes that you have a class called SpringApplicationContextInstance that gives you the spring context using which you can access your beans defined in spring context.

...
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

/**
* Created by Shreyas Purohit
*
*/
public class JMSContainerShutDownHook implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
LogManager.log(Level.INFO, "JMSContainerShutDownHook: Initialized called");
}

@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
LogManager.log(Level.INFO, "JMSContainerShutDownHook: Destroyed called");
try {
LogManager.log(Level.INFO, "JMSContainerShutDownHook: Fetching JMS Container Bean from Application Context");
DefaultMessageListenerContainer container = SpringApplicationContextInstance.getInstance().getBean("jmsContainer");
LogManager.log(Level.INFO, "JMSContainerShutDownHook: Calling shutdown on DefaultMessageListenerContainer");
container.shutdown();
Thread.sleep(3000); //Wait for the container to shutdown
} catch (Exception e) {
e.printStackTrace();
LogManager.log(Level.ERROR, e);
}
LogManager.log(Level.INFO, "JMSContainerShutDownHook: Exiting");
}
}

No comments:

Post a Comment