Pianificazione a Jakarta EE

1. Panoramica

In un articolo precedente, abbiamo dimostrato come pianificare le attività in Spring utilizzando@Programmatoannotazione. In questo articolo, dimostreremo come ottenere lo stesso risultato utilizzando il servizio timer in un'applicazione Jakarta EE per ogni caso presentato nell'articolo precedente.

2. Abilitare il supporto per la pianificazione

In un'applicazione Jakarta EE, non è necessario abilitare il supporto per le attività a tempo. Il servizio timer è un servizio gestito dal contenitore che consente alle applicazioni di chiamare metodi pianificati per eventi basati sul tempo. Ad esempio, un'applicazione potrebbe dover eseguire alcuni rapporti giornalieri a una determinata ora per generare statistiche.

Esistono due tipi di timer:

  • Timer programmatici : il servizio timer può essere iniettato in qualsiasi bean (eccetto un bean di sessione stateful) e la logica di business dovrebbe essere collocata in un metodo annotato con @Timeout . Il timer può essere inizializzato da un metodo annotato @PostConstruct dei bean oppure può anche essere inizializzato semplicemente chiamando un metodo.
  • Timer automatici : la logica di business viene inserita in qualsiasi metodo annotato con @Schedule o @Schedules . Questi timer vengono inizializzati non appena viene avviata l'applicazione.

Quindi iniziamo con il nostro primo esempio.

3. Pianifica l'attività con un ritardo fisso

In primavera questo viene fatto semplicemente utilizzando l' annotazione @Scheduled (fixedDelay = 1000) . In questo caso, viene fissata la durata tra la fine dell'ultima esecuzione e l'inizio della successiva. L'attività attende sempre fino al termine di quella precedente.

Fare esattamente la stessa cosa in Jakarta EE è un po 'più difficile da ottenere perché non è previsto un meccanismo integrato simile, tuttavia, uno scenario simile può essere implementato con un po' di codice extra. Diamo un'occhiata a come si fa:

@Singleton public class FixedTimerBean { @EJB private WorkerBean workerBean; @Lock(LockType.READ) @Schedule(second = "*/5", minute = "*", hour = "*", persistent = false) public void atSchedule() throws InterruptedException { workerBean.doTimerWork(); } } 
@Singleton public class WorkerBean { private AtomicBoolean busy = new AtomicBoolean(false); @Lock(LockType.READ) public void doTimerWork() throws InterruptedException { if (!busy.compareAndSet(false, true)) { return; } try { Thread.sleep(20000L); } finally { busy.set(false); } } }

Come puoi vedere, il timer è programmato per essere attivato ogni cinque secondi. Tuttavia, il metodo attivato nel nostro caso ha simulato un tempo di risposta di 20 secondi chiamando sleep () sul Thread corrente .

Di conseguenza, il contenitore continuerà a chiamare doTimerWork () ogni cinque secondi ma la condizione posta all'inizio del metodo, busy.compareAndSet (false, true), tornerà immediatamente se la chiamata precedente non è terminata. In questo, ci assicuriamo che l'attività successiva verrà eseguita solo al termine di quella precedente.

4. Pianifica l'attività a un tasso fisso

Un modo per farlo è usare il servizio timer che viene iniettato usando @Resource e configurato nel metodo annotato @PostConstruct . Il metodo annotato con @Timeout verrà chiamato quando il timer scade.

Come accennato nell'articolo precedente l'inizio dell'esecuzione dell'attività non attende il completamento dell'esecuzione precedente. Questa opzione dovrebbe essere utilizzata quando ogni esecuzione dell'attività è indipendente. Lo snippet di codice seguente crea un timer che si attiva ogni secondo:

@Startup @Singleton public class ProgrammaticAtFixedRateTimerBean { @Inject Event event; @Resource TimerService timerService; @PostConstruct public void initialize() { timerService.createTimer(0,1000, "Every second timer with no delay"); } @Timeout public void programmaticTimout(Timer timer) { event.fire(new TimerEvent(timer.getInfo().toString())); } }

Un altro modo è utilizzare l' annotazione @Scheduled . Nello snippet di codice seguente attiviamo un timer ogni cinque secondi:

@Startup @Singleton public class ScheduleTimerBean { @Inject Event event; @Schedule(hour = "*", minute = "*", second = "*/5", info = "Every 5 seconds timer") public void automaticallyScheduled(Timer timer) { fireEvent(timer); } private void fireEvent(Timer timer) { event.fire(new TimerEvent(timer.getInfo().toString())); } }

5. Pianifica l'attività con ritardo iniziale

Se il tuo caso d'uso richiede che il timer si avvii con un ritardo, possiamo farlo anche noi. In questo caso Jakarta EE consente l'utilizzo del servizio timer. Diamo un'occhiata a un esempio in cui il timer ha un ritardo iniziale di 10 secondi e poi si attiva ogni cinque secondi:

@Startup @Singleton public class ProgrammaticWithInitialFixedDelayTimerBean { @Inject Event event; @Resource TimerService timerService; @PostConstruct public void initialize() { timerService.createTimer(10000, 5000, "Delay 10 seconds then every 5 seconds timer"); } @Timeout public void programmaticTimout(Timer timer) { event.fire(new TimerEvent(timer.getInfo().toString())); } }

Il metodo createTimer utilizzato nel nostro esempio utilizza la seguente firma c reateTimer (long initialDuration, long intervalDuration, java.io.Serializable info) dove initialDuration è il numero di millisecondi che devono trascorrere prima della prima notifica di scadenza del timer e intervalDuration è il numero di millisecondi che devono trascorrere tra le notifiche di scadenza del timer.

In questo esempio, stiamo usando una initialDuration di 10 secondi e un intervalloDuration di cinque secondi. L'attività verrà eseguita per la prima volta dopo il valore initialDuration e continuerà a essere eseguita in base a intervalDuration .

6. Pianifica l'attività utilizzando le espressioni Cron

Tutti gli scheduler che abbiamo visto, sia programmatici che automatici, consentono l'utilizzo di espressioni cron. Vediamo un esempio:

@Schedules ({ @Schedule(dayOfMonth="Last"), @Schedule(dayOfWeek="Fri", hour="23") }) public void doPeriodicCleanup() { ... }

In questo esempio il metodo doPeriodicCleanup () verrà chiamato ogni venerdì alle 23:00 e l'ultimo giorno del mese.

7. Conclusione

In questo articolo abbiamo esaminato vari modi per pianificare le attività nell'ambiente EE di Jakarta utilizzando come punto di partenza un articolo precedente in cui gli esempi sono stati eseguiti utilizzando Spring.

Esempi di codice possono essere trovati nel repository GitHub.