61

I am not very familiar with Tomcat, in my head it is basically abstracted as a cgi server that saves the JVM between calls -- I know it can do a lot more than that, though.

I am looking for a way to launch a background thread when a Tomcat server starts, which would periodically update the Server Context (in my particular case this is a thread that listens to heartbeats from some other services and updates availability information, but one can imagine a variety of uses for this).

Is there a standard way to do this? Both the launching, and the updating/querying of the Context?

Any pointers to the relevant documentation and/or code samples would be much appreciated.

SquareCog
  • 18,663
  • 6
  • 46
  • 61
  • It's worth noting that you can generally just start a thread when you want to if there's a more convenient place to do so than when the context is initialised. E.g. it could be in the init method of a particular servlet, or when a particular class is first initted etc. – Neil Coffey Apr 27 '09 at 05:34

5 Answers5

80

If you want to start a thread when your WAR is deployed, you can define a context listener within the web.xml:

<web-app>
    <listener>
       <listener-class>com.mypackage.MyServletContextListener</listener-class>
    </listener>
</web-app>

Then implement that class something like:

public class MyServletContextListener implements ServletContextListener {

    private MyThreadClass myThread = null;

    public void contextInitialized(ServletContextEvent sce) {
        if ((myThread == null) || (!myThread.isAlive())) {
            myThread = new MyThreadClass();
            myThread.start();
        }
    }

    public void contextDestroyed(ServletContextEvent sce){
        try {
            myThread.doShutdown();
            myThread.interrupt();
        } catch (Exception ex) {
        }
    }
}
Darwin
  • 4,264
  • 2
  • 27
  • 22
Chris Thornhill
  • 5,011
  • 1
  • 21
  • 21
  • Ah! Thanks, that's very straightforward. Am I correct in saying that "ServletContext" is what I need to modify to have this thread pass information to my servlet, so it can use the statuses my heartbeat listener collects? – SquareCog Apr 27 '09 at 01:52
  • 1
    Yes, missed this part in my answer. :) The ServletConext is available from the ServletContextEvent, which could be passed into the your Thread object which could get/set attributes available to all threads. – Chris Thornhill Apr 27 '09 at 02:07
  • At that point, how is it possible to access the `MyServletContextListener` to query the thread? – Daniele Orlando Nov 23 '16 at 15:04
12

I am looking for a way to launch a background thread when a Tomcat server starts

I think you are looking for a way to launch a background thread when your web application is started by Tomcat.

This can be done using a ServletContextListener. It is registered in web.xml and will be called when your app is started or stopped. You can then created (and later stop) your Thread, using the normal Java ways to create a Thread (or ExecutionService).

Thilo
  • 241,635
  • 91
  • 474
  • 626
5

Putting <load-on-startup>1</load-on-startup> in the <servlet> block in your web.xml will force your servlet's init() to happen as soon as Tomcat starts up, rather than waiting for the first request to arrive. This is useful if you want to spawn the background thread from init().

sixones
  • 1,853
  • 4
  • 21
  • 25
divbyzero
  • 51
  • 1
  • 1
  • This did the trick for me, so simple in comparison to other solutions here, yet so unrated and well suited for starting some background apps or daemons. Thanks! – Arturas M Apr 09 '16 at 11:22
2

I'd just make a small change to the very detailed answer Chris gave; I would set myThread to be a Daemon thread by myThread.setDaemon(true); which will basically keep the thread active as long as you have other non-Daemon threads working which need your background thread around. When all these threads finish then your Daemon thread is stopped by the JVM and you do not need to handle it youself in contextDestroyed. But that's just my 2 cents.

Ittai
  • 4,835
  • 11
  • 54
  • 90
  • 13
    Except you still need to handle it in contextDestroyed. Daemons terminate when the last non-daemon thread terminates, not when the servlet context terminates. If you deploy a WAR file to replace one that's currently running, the daemon thread from the old servlet context will keep running. That in turn keeps that context's ClassLoader around, which is a PermGen memory leak, which is bad. – David Leppik Jan 17 '13 at 20:57
2

Another way if you are using spring based framework you can specify the class/thread which you want to initialize in the beans.xml. So when the tomcat starts up, beans.xml will initialize all the classes mentioned in it. You can also pass constructor arguments if required. Below is the example of the same.

beans.xml

<bean id="monitoringSvc" class="com.mypackage.MonitoringService">
    <constructor-arg value="60"></constructor-arg>
</bean>

MonitoringService.java

public class MonitoringService{

     private MyThread myThread;

     public MonitoringService(int seconds){
          myThread = new MyThread(seconds);
          myThread.start();
     }
}    
Akshay
  • 508
  • 1
  • 5
  • 14