1

In a existing project, I want to start a new thread when tomcat starts. In the new thread, I will do something like setup a timer and call web service every 5 minutes.

I don't know where I can create this thread, and how to execute a method inside the thread.

Is there a web.xml configuration for this? Or something else? Thank you.

Sotirios Delimanolis
  • 252,278
  • 54
  • 635
  • 683
Tech Noob
  • 522
  • 1
  • 8
  • 24
  • just for curiosity why you need a thread for that , you can write a job , there are lot of scheduler frameworks available e.g the one I love most `Quartz` - thanks – saurav Aug 08 '13 at 21:08

3 Answers3

4

You have a few options.

Use a ServletContextListener and start and stop the thread in contextInitialized() and contextDestroyed() methods respectively.

In a Servlet or Filter start and stop the thread in the init() and destroy() methods respectively.

If you don't know how Thread class works, read the class' javadoc here. Create your own implementation of a Runnable and pass that to the Thread, then start() it.

On a related note, don't manage the thread yourself. Use an ExecutorService.

Sotirios Delimanolis
  • 252,278
  • 54
  • 635
  • 683
  • So what is the difference between using ServletContextListener or Servlet or filter? I am new to this industry, thank you for your patient, this really helped. – Tech Noob Aug 09 '13 at 13:25
  • Servlets and Filters process requests. A ServletContextListener is useful to setup your whole application and manage the lifecycle of your objects. – Sotirios Delimanolis Aug 09 '13 at 13:39
  • I got it. So the ServletContextListener is always application scope? I saw in a existing project, someone write a comment on the listener in web.xml, it says "session listeners", is this wrong? Or he means something else? Thank you. – Tech Noob Aug 09 '13 at 14:11
  • `ServletContextListener` is attached to the lifecycle of the application context. There are many different kinds of Listeners. An `HttpSessionListener` is attached to the lifecycle of an `HttpSession`. See [here](http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpSessionListener.html). – Sotirios Delimanolis Aug 09 '13 at 14:14
  • Oh I see they are using different interfaces. I got another question here. I have create a application context scope listener, and I used `ExecutorService` to execute the `Runnalbe` class. Now if I want to maintain a static Map in application scope and make it accessible from the whole application(like inside the servlets). Where should I create this static Map and how can I access it. It should be inside the `Runnable `class? Or just in the `Listener`? Thank you very much. – Tech Noob Aug 09 '13 at 14:54
  • Where you create it is up to you (probably in `contextInitialized()` or one of the `init()`s). Where you put is in the [`ServletContext`](http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContext.html). You can use `setAttribute(String, Object)` to hold a reference to the map which you can access from pretty much anywhere. In the `ServletContextListener`, you have a reference to a `ServletContextEvent` from which you can access the `ServletContext`. – Sotirios Delimanolis Aug 09 '13 at 15:09
3

These days I really don't think you really need to create a new thread like this new Thread() when you have ExecutorService from the java.util.concurrent package is available at your disposal.

For starting a new thread you can define your contextListener in web.xml like this -

<listener>
   <listener-class>com.techidiocy.IdiotContextListener</listener-class>
</listener>

And definition of this listener will be something like this -

public class IdiotContextListener implements ServletContextListener {

private IdiotThreadClass idiotThread= null;

public void contextInitialized(ServletContextEvent sce) {
    //Your logic for starting the thread goes here - Use Executor Service
}

public void contextDestroyed(ServletContextEvent sce){
   //Your logic for shutting down thread goes here
  }
}

Moreover , having <load-at-startup>1</load-at-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().

saurav
  • 3,173
  • 1
  • 20
  • 32
2

You can do that with Quartz.

Example

Project structure for this example is:

C:.
|
+---src
|   |   quartz.properties
|   |   quartz_data.xml
|   |
|   \---org
|       \---paulvargas
|           \---test
|               \---quartz
|                       TestJob.java
|
\---WebContent
    \---WEB-INF
        |   web.xml
        |
        \---lib
                jta-1.1.jar
                log4j-1.2.17.jar
                quartz-2.1.5.jar
                slf4j-api-1.6.5.jar
                slf4j-log4j12-1.6.5.jar

TestJob.java

This file may contents the call to WebService.

package org.paulvargas.test.quartz;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class TestJob implements Job {

    @Override
    public void execute(final JobExecutionContext ctx) 
            throws JobExecutionException {
        System.out.println("Call to WebService");
    }

}

quartz_data.xml

In this file you put a cron expression (you can build it with http://www.cronmaker.com/)

<?xml version="1.0" encoding="UTF-8"?>

<job-scheduling-data
    xmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd"
    version="1.8">

    <schedule>
        <job>
            <name>TestJob</name>
            <job-class>org.paulvargas.test.quartz.TestJob</job-class>
        </job>
        <trigger>
            <cron>
                <name>TestJob</name>
                <job-name>TestJob</job-name>
                <cron-expression>0 0/5 * 1/1 * ? *</cron-expression>
            </cron>
        </trigger>
    </schedule>

</job-scheduling-data>

quartz.properties

# ----------------------------- Threads --------------------------- #
org.quartz.threadPool.threadCount=5

# ----------------------------- Plugins --------------------------- #
org.quartz.plugin.jobInitializer.class=org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">

    <listener>
        <listener-class>org.quartz.ee.servlet.QuartzInitializerListener</listener-class>
    </listener>

</web-app>

I hope this can help you. Good luck!

Paul Vargas
  • 38,878
  • 15
  • 91
  • 139