Wie eine Hintergrundaufgabe in einer Servlet-basierten Web-Anwendung laufen zu lassen?
Frage
Ich bin mit Java und ich möchte ein Servlet halten ständig in meiner Anwendung ausgeführt wird, aber ich bin nicht immer, wie es geht. Mein Servlet hat eine Methode, die Zählungen des Benutzers aus einer Datenbank auf einer täglichen Basis, sowie die Gesamtzahl der Nutzer aus der gesamten Datenbank gibt. Also habe ich das Servlet kontinuierlich laufen für das halten wollen.
Lösung
Ihr Problem ist, dass Sie mißverstehen der Zweck des Servlet . Es ist zu handeln intented auf HTTP-Anfragen, nichts weiter. Sie wollen einfach nur eine Hintergrundaufgabe, die auf täglicher Basis einmal ausgeführt wird.
EJB zur Verfügung? Verwenden Sie @Schedule
Wenn Sie Ihre Umgebung zu unterstützen EJB geschehen (dh eine echte Java EE-Server wie Wildfly, JBoss, TomEE, Payara, Glassfish, etc), dann verwenden Sie @Schedule
statt. Hier sind einige Beispiele:
@Singleton
public class BackgroundJobManager {
@Schedule(hour="0", minute="0", second="0", persistent=false)
public void someDailyJob() {
// Do your job here which should run every start of day.
}
@Schedule(hour="*/1", minute="0", second="0", persistent=false)
public void someHourlyJob() {
// Do your job here which should run every hour of day.
}
@Schedule(hour="*", minute="*/15", second="0", persistent=false)
public void someQuarterlyJob() {
// Do your job here which should run every 15 minute of hour.
}
@Schedule(hour="*", minute="*", second="*/5", persistent=false)
public void someFiveSecondelyJob() {
// Do your job here which should run every 5 seconds.
}
}
Ja, das ist wirklich alles. Der Container wird automatisch Pick-up und verwaltet sie.
EJB nicht verfügbar? Verwenden Sie ScheduledExecutorService
Wenn Ihre Umgebung nicht unterstützt EJB (dh Sie nicht keine echten Java EE-Server verwenden, aber ein Barebone servletcontainer wie Tomcat, Jetty, etc), dann verwenden Sie ScheduledExecutorService
. Dies kann durch eine eingeleitet werden ServletContextListener
. Hier ist ein Kick-off-Beispiel:
@WebListener
public class BackgroundJobManager implements ServletContextListener {
private ScheduledExecutorService scheduler;
@Override
public void contextInitialized(ServletContextEvent event) {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 1, TimeUnit.DAYS);
scheduler.scheduleAtFixedRate(new SomeHourlyJob(), 0, 1, TimeUnit.HOURS);
scheduler.scheduleAtFixedRate(new SomeQuarterlyJob(), 0, 15, TimeUnit.MINUTES);
scheduler.scheduleAtFixedRate(new SomeFiveSecondelyJob(), 0, 5, TimeUnit.SECONDS);
}
@Override
public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdownNow();
}
}
Wenn die Job-Klassen wie folgt aussehen:
public class SomeDailyJob implements Runnable {
@Override
public void run() {
// Do your daily job here.
}
}
public class SomeHourlyJob implements Runnable {
@Override
public void run() {
// Do your hourly job here.
}
}
public class SomeQuarterlyJob implements Runnable {
@Override
public void run() {
// Do your quarterly job here.
}
}
public class SomeFiveSecondelyJob implements Runnable {
@Override
public void run() {
// Do your quarterly job here.
}
}
Denken Sie nicht immer über die Verwendung von java.util.Timer
/ java.lang.Thread
in einer Java EE / Servlet-basierten Umgebung
Last but not least, nie direkt verwenden java.util.Timer
und / oder java.lang.Thread
in Java EE. Dies ist Rezept für Ärger. Eine aufwendige Erklärung kann in diesem JSF-bezogene Antwort auf die gleiche Frage zu finden: Laichen Threads in einer JSF Managed Bean für geplante Tasks eines Timer verwendet wird.
Andere Tipps
Ich würde vorschlagen, eine Bibliothek wie Quarz, um mit der Aufgabe, in regelmäßigen Abständen zu laufen. Was macht das Servlet wirklich? Es sendet Ihnen einen Bericht?
Implementieren Sie zwei Klassen und Call startTask()
in main
.
public void startTask()
{
// Create a Runnable
Runnable task = new Runnable() {
public void run() {
while (true) {
runTask();
}
}
};
// Run the task in a background thread
Thread backgroundThread = new Thread(task);
// Terminate the running thread if the application exits
backgroundThread.setDaemon(true);
// Start the thread
backgroundThread.start();
}
public void runTask()
{
try {
// do something...
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Sie können cron4j verwenden. http://www.sauronsoftware.it/projects/cron4j/manual.php
In einem Produktionssystem, die mehr nicht-jee Behälter laufen kann. Verwenden Sie Anot Enterprise Scheduler wie Quartz Scheduler, die so konfiguriert werden kann, eine Datenbank für die Aufgabe maamgememt zu verwenden.