Potocznie Cronem nazwiemy proces uruchamiający programy cyklicznie lub o określonej porze.
Może być zdefiniowany systemowo, np w systemie linux:
Lub programowo (przez bibliotekę) np :
Quartz jest biblioteką Javy do definiowania zadań i ich uruchamiania zgodnie z zadanym terminarzem. Może także być wykorzystywana do tworzenia zdarzeń cyklicznych w typie zadań Crona.
Strona główna podpowiada nam, że by zacząć pracę z biblioteką należy zdefiniować następujące zależności:
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
Przez Job będziemy nazywać klasę, którą będziemy mogli uruchamiać wiele razy za pomocą schedulera / crona.
Job jest to klasa która implementuje interfejs org.quarts.Job (czyli innymi słowy posiadającą metodę execute()). Będzie ona uruchamiana przy uruchomieniu zadania. Do obiektu Job przekazywany jest obiekt JobExecutionContext posiadający informacje o zmiennych środowiskowych oraz wywołaniu.
public class MyJob implements org.quartz.Job {
public MyJob() {
}
public void execute(JobExecutionContext context) throws JobExecutionException {
System.err.println("Hello World! MyJob is executing.");
}
}
Zanim użyjemy Schedulera musimy stworzyć jego instancję, aby to zrobić korzystamy z SchedulerFactory. Scheduler możemy wystartować, przełączyć w tryb stand-by oraz wyłączyć. Zadania nie są uruchamiane dopóki Scheduler nie zostanie uruchamiany jak i nie są uruchamiane gdy jest on zatrzymany.
Elementy Quartz API:
Scheduler - główna klasa Schedulera,Job - interfejs, który musi implementować zadanie,JobDetail - definiuje instance zadania i jego własności,Trigger - definiuje harmonogram uruchamiania zadań,
Podstawowy przykład:
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;
import static org.quartz.JobBuilder.*;
import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
public class QuartzTest {
public static void main(String[] args) {
try {
// Grab the Scheduler instance from the Factory
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// and start it off
scheduler.start();
// define the job and tie it to our HelloJob class
JobDetail job = newJob(HelloJob.class)
.withIdentity("job1", "group1")
.build();
// Trigger the job to run now, and then repeat every 1 seconds
Trigger trigger = newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(simpleSchedule()
.withIntervalInSeconds(1)
.repeatForever())
.build();
// Tell quartz to schedule the job using our trigger
scheduler.scheduleJob(job, trigger);
scheduler.shutdown();
} catch (SchedulerException se) {
se.printStackTrace();
}
}
}
Wykonaj
Wejdź na branch Feature/ThirdClass. Uruchom klasę SimpleScheduler z repozytorium, zobacz jak on działa i jak wywoływane są zadania.
SimpleTrigger służy do pojedynczego uruchomienia zadania lub jeżeli chcesz je uruchamiać N razy w odstępach czasu T. CronTrigger jest przydatny w przypadku, gdy zadania są uruchamiane zgodnie z kalendarzem np “w każdy piątek, w południe” or “o 10:15 10-tego dnia miesiąca.”
Za każdym razem gdy zadanie jest wykonywane tworzona jest nowa instancja obiektu Job, w związku z tym nie możemy zapisywać danych między kolejnymi uruchomieniami klasy wewnątrz klasy zadania.
Jeżeli chcemy przekazywać jakieś parametr do zadania możemy to robić poprzez klasę JobDetail.
JobDataMap jest mapą obiektów związanych z JobDetail.
Przykład:
// define the job and tie it to our DumbJob class
JobDetail job = newJob(DumbJob.class)
.withIdentity("myJob", "group1") // name "myJob", group "group1"
.usingJobData("jobSays", "Hello World!")
.usingJobData("myFloatValue", 3.141f)
.build();
Implementacja zadania:
@PersistJobDataAfterExecution
public class DumbJob implements Job {
public DumbJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException
{
JobKey key = context.getJobDetail().getKey();
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue");
System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
}
}
Aby JobDataMap był kopiowany między kolejnymi wywołaniami zadania musimy ustawić przed definicją klasy adnotację @PersistJobDataAfterExecution.
Wykonaj
Uruchom klasę JobMapScheduler z repozytorium, zobacz jak zdefiniowana jest klasa JobWithMap, jak zapisywane i odczytywane są wartości z JobDataMap.
Elementy trigerów to:
withIdentity - nazwa trigera, ew. nazwa grupy do której należy (możemy grupować trigery),startAt - czas startu (ew. startNow()),withSchedule - harmonogram uruchomienia.
Do definicji przetwarzania crona używany tzw. cron expression. Cron-Expressions to napis złożony z siedmiu części oddzielonych spacją, wyznaczających szczegóły harmonogramu, kolejno
SecondsMinutesHoursDay-of-MonthMonthDay-of-WeekYear (optional field)
Np. "0 0 12 ? * WED” - oznacza “w każdą środę 0 12:00:00 pm”.
Kazde pole może zawierać zakres lub listę elementów po przecinku. Np. dzień tygodnia może otrzymać wartość "WED” jak i “MON-FRI”, “MON,WED,FRI”, czy też “MON-WED,SAT”.
Znak ‘*’ oznacza każdą możliwą wartość
Znak ‘?’ można wykorzystać dla day-of-month oraz day-of-week w przypadku gdy jeden z tych elementów przyjmuje specyficzną wartość a drugi chcemy żeby nie przyjmował żadnej wartości konkretnej (jak w przykładzie powyżej).
Więcej informacji można przeczytać tutaj:
Obszerna lista przykładów definicji cron schedulera :
Projekt z zakresu 1-2
Stworzenie programu, który będzie tworzyć listę zapytań SQL i zapisywać je do pliku.
Użytkownik podaje numer zadania i w kolejnej linii zapytanie SQL (takie jak odpowiedź na zadanie z Baz Danych). Zakładamy, ze użytkownik zawsze wpisze poprawny numer jednak zapytanie SQL powinno być w prostu sposób parsowane (poprzez wyszukanie słów kluczowych SELECT, FROM, WHERE, ORDER BY i określenie czy podane były w danej kolejności, czy w złym porządku). W przypadku złego porządku odpowiedź nie jest zapisywana a użytkownik otrzymuje komunikat o błędzie.
Każde uruchomienie tworzy nowy plik odpowiedzi (program nie odczytuje żadnych danych).
W przypadku podania dwa razy tego samego numeru zadania odpowiedź jest nadpisywana.
co 30 sekund licząc od pełnych minut wpisane odpowiedzi zostają automatycznie zapisane do pliku odp.txt. Odpowiedzi w pliku mają być posortowane względem numerów zadań. (Uwaga! Użytkownik może w programie wpisywać odpowiedzi w dowolnej kolejności).
co pełną minutę od Pn-PT w godzinach 8.15-18.45 będzie pokazywać na ekranie komunikat "X minut do końca zajęć/przeryw". Zamodeluj godziny zajęć i przerw jak na WMI UAM.
Napisz testy do danych klas - co najmniej dla metody sprawdzającej poprawność zapytania SQL, oraz metody sprawdzającej czy dany czas jest przerwą czy zajęciami.
Proponuję kod tworzyć u siebie na repozytorium w gałęzi master.
Wykorzystano materiały z: