CronJobs mit Spring
Mit Spring können zeitgesteuerte Aufgaben in Java Code integriert werden. CronJobs wie wir sie in Linux kennen, definieren wir mit Spring einfach per Annotation. In diesem Artikel zeige ich wie das geht und wie Spring die CronJobs entsprechend unserer Definition ausführt.
Was ist ein CronJob?
Unter CronJob verstehen wir die zeitlich gesteuerte Ausführung eines Kommandos zur Erledigung einer Aufgabe bzw. eines Jobs. Das Kommando wird durch einen bestimmten Zeitpunkt oder eine zeitliche Bedingung angestoßen.
Typische Beispiele für durch CronJobs gestartete Aufgaben sind:
- Regelmäßiges Aufräumen der Datenbank - z. B. um veraltete Daten zu löschen oder DSGVO konform persönliche Daten nach einer definierten Zeit zu löschen.
- Wöchentlicher Versand von Newslettern oder Werbung per Email
- Nächtliche Datenbank-Backups
- Monatliches Erstellen von Rechnungen (z.B. Telefon-Rechnung)
CronJobs mit Spring
Das Spring Framework bietet Entwickler eine Scheduling-Funktionalität zum Erstellen von CronJobs. Scheduling ist Teil der Spring Kern-Funktionalitäten, daher werden keine weiteren Build-Dependencies bzw. Bibliotheken benötigt. Einen einzelnen CronJob legen wir einfach in einer einzigen Klasse an und konfigurieren per Annotation:
@EnableScheduling
@Configuration
public class ScheduledJobs {
Logger log = Logger.getLogger("ScheduledJobs");
@Scheduled(cron = "1 * * * * *")
private void logEvery1stSecond() {
log.log(Level.INFO,
"CronJob executed every 1st second" +
"of any minute at any day");
}
}
- @EnableScheduling aktiviert die Spring Scheduling Fähigkeit für die komplette Spring Anwendung. Sie sollte zusammen mit der @Configuration Annotation gesetzt werden. Sie muss nicht zusammen mit den CronJob-Methoden in derselben Klasse sein.
- @Scheduled markiert eine Methode, so dass sie vom Spring Scheduler entsprechend ihrer Konfiguration ausgeführt wird. Hier verwende ich eine einfache CronJob-Konfiguration, welche die Methode in der ersten Sekunden jeder beliebigen Minute ausführt.
cron = "1 * * * * *" definiert durch die Sterne (*), dass Minute, Stunde, Tag, Monat und Wochentag beliebig sind.
Das cron-Attribut
Das cron-Attribute der Scheduled Annotation ist ähnlich dem Linux crontab aufgebaut. In Spring hat es 6 Leerzeichen-separierte Werte und somit dieses Format:
<Sekunde> <Minute> <Stunde> <Tag des Monats> <Monat> <Tag der Woche>
Weitere Beispiele für das cron-Attribut:
- @Scheduled(cron = "1-10 */2 * * * Mon-Fri")
- 1-10 legt fest, dass die annotierte Methode in den Sekunden 1 bis 10 aufgerufen wird. Das Minuszeichen definiert eine Spanne und legt hier fest, dass die Methode nur an den Werktagen Montag bis Freitag in einer Woche ausgeführt wird.
- */2 legt fest, dass der CronJob nur jede 2. Minute ausgeführt wird. Würde man statt dem Stern eine Zahl festlegen, z.B. 5/2 so würde der Job ab der 5. Minute jede 2 Minute ausgeführt.
- @Scheduled(cron = "0 0 0 25 12 ?", zone = "Europe/Berlin")
- Dieser CronJob wird einmal im Jahr am ersten Weihnachtstag, dem 25.12. um 0:00 Uhr ausgeführt.
- Mit dem zone Attribut kann man noch die Zeitzone festlegen, also hier die deutsche Zeitzone.
- Der Wochentag kann durch ein Fragezeichen als irrelevant markiert werden.
- @Scheduled(cron = "11,22,33,44,55 * * * * *")
- Die Komma-separierte Liste definiert in welchen Sekunden dieser CronJob ausgeführt wird.
- @Scheduled(cron = "1-10,15,30,45 * * * * ?")
- Kombinationen sind auch möglich.
Relative Abstände zwischen CronJobs
- Wenn CronJobs mit Spring definiert und ausgeführt werden, können sie auf den Spring IoC Container und somit alle Beans zugreifen. Hier wurde eine IdGenerator Bean mit @Autowired injiziert. Weitere Infos zu Beans und Dependency Injektion findet ihr hier: kernkonzepte-von-spring.html
- initialDelay legt fest wie viele Millisekunden nach Start der Spring Anwendung der CronJob zum ersten Mal startet.
- fixedDelay definiert wie viele Millisekunden gewartet wird, bevor der CronJob erneut nach Ende der vorherigen CronJobs-Ausführung startet. Im Code-Beispiel oben ist zwischen den Ausführungen des CronJobs immer 1 Sekunde bzw. 1000 Millisekunden Pause.
- fixedRate zeige ich im Zusammenhang mit asynchroner Ausführung von CronJobs. Das Attribut fixedRate legt fest wie viele Millisekunden Abstand zwischen dem Start zweier CronJobs ist.
Asynchrone Ausführung von CronJobs
initialDelayString = "${scheduled.initial-delay}")
- Um CronJobs asynchron durch den Spring Scheduler auszuführen, muss zur @EnableScheduling Annotation auch die @EnableAsync in einer Konfiguration-Klasse gesetzt werden.
- Jede @Scheduled annotierte Methode, die asynchron zu anderen CronJobs ausgeführt werden soll, benötigt die @Async Annotation. Danach startet sie der Spring Scheduler in einem separaten Thread.
- Die String-Attribute (inklusive cron-Attribut) der @Scheduled Annotation, können aus den Spring Properties Dateien gelesen werden. Dazu schreibt man den Properties-Schlüssel in ${...}. Spring geht alle Property Definitionen durch, um den Wert passend zum Schlüssel zu finden. Meine application.properties Datei zu diesem Beispiel sieht so aus:
Fazit
Die Scheduling Fähigkeit von Spring ist sehr gut ins Spring Framework integriert und einfach zu benutzen. Falls ihr Linux CronJobs kennt, versteht ihr alles schnell.
In der Praxis verwende ich die Scheduling Fähigkeit von Spring, um alte Daten aus der Datenbank zu löschen. Dazu verwende ich einfach die vorhandene Beans, die JPA Entitäten und die Datenbank Connection innerhalb des CronJobs.
Den kompletten Code findet ihr in GitHub:
https://github.com/elmar-brauch/beans/tree/master/src/main/java/de/bsi/bean/schedule
Kommentare