Come eseguire un task in background in un'applicazione web basata servlet?
Domanda
Sto usando Java e voglio mantenere un servlet in esecuzione continua nella mia richiesta, ma non sto ottenendo come farlo. La mia servlet ha un metodo che dà i conteggi degli utenti da un database su una base quotidiana, così come il numero totale degli utenti di tutto il database. Quindi voglio mantenere il servlet in esecuzione continua per questo.
Soluzione
Il problema è che si fraintendere lo scopo della servlet . E 'intented ad agire per le richieste HTTP, niente di più. Si vuole solo un task in background che viene eseguito una volta su base giornaliera.
EJB disponibili? Utilizzare @Schedule
Se l'ambiente capita di supporto EJB (ad esempio un server Java EE reale come wildfly, JBoss, TomEE, Payara, GlassFish, ecc), quindi utilizzare @Schedule
. Ecco alcuni esempi:
@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.
}
}
Sì, questo è davvero tutto. Il contenitore viene automaticamente pick-up e gestirlo.
EJB non è disponibile? Utilizzare ScheduledExecutorService
Se l'ambiente non EJB non il supporto (per esempio, si sta utilizzando non è non un vero e proprio server di Java EE, ma un barebone servletcontainer come Tomcat, Jetty, ecc), quindi utilizzare ScheduledExecutorService
. Questo può essere avviata da un ServletContextListener
. Ecco un esempio kickoff:
@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();
}
}
Se le classi di lavoro simile a questa:
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.
}
}
Non bisogna mai pensare di utilizzare java.util.Timer
/ java.lang.Thread
in un ambiente basato su Java EE / Servlet
Ultimo ma non meno importante, non utilizzare direttamente java.util.Timer
e / o java.lang.Thread
in Java EE. Questa è la ricetta di guai. Una spiegazione elaborata può essere trovato in questa risposta JSF-correlate sulla stessa domanda: Deposizione thread in un bean gestito JSF per attività pianificate usando un timer .
Altri suggerimenti
Io suggerirei di usare una libreria come al quarzo, al fine di eseguire l'operazione a intervalli regolari. Che cosa fa il servlet davvero fare? Esso si invia un rapporto?
Implementare due classi e chiamata 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();
}
}
È possibile utilizzare cron4j. http://www.sauronsoftware.it/projects/cron4j/manual.php
In un sistema di produzione che può avere molteplici contenitori non jee esecuzione. Utilizzare anot scheduler un'impresa come quarzo di pianificazione che può essere configurato per utilizzare un database per l'attività maamgememt.