Ersatz für Cronjobs: Spring Framework und Quartz Scheduler (Permalink)

Manche Funktionen von Webapplikationen sollen regelmässig ausgeführt werden. Das könnte ein täglicher Report per Mail über die Anzahl der neuen Kunden, das Mahnen von unbezahlten Rechnungen und vieles weiteres. Auf unixoiden Betriebsystemen erledigt klassischerweise Cron solche Aufgaben.

Die Alternative: Spring Framework und Quartz Scheduler

Quartz Scheduler ist ein in Java geschriebener Ersatz für Cron und kann einfach in beliebige Java-Anwendungen integriert werden. Das Spring Framework bietet Unterstützung für Quartz an.

Hier soll nun gezeigt werden, wie eine einfache Integration aussehen kann.

Änderungen an der pom.xml

Folgende Abhängigkeiten müssen eingefügt werden.

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>1.8.6</version>
</dependency>

Wichtig ist hierbei, das zur Zeit (Ende September 2012) Spring 3.x und Quartz 2.x zueinander inkompatibel sind. Dies ist auch in folgendem Bug einsehbar: SPR-858.

Schreiben der ausgeführten Funktion

Hier reicht, wie für das Spring Framework üblich, ein klassisches POJO.

package de.lusiardi.quartzdemo;
public class CalledService {
   public void calledMethod() {
       System.out.println("Executed by Quartz");
   }
}

In dieser POJO können natürlich weitere Beans über Autowiring angesprochen werden wie in jeder Spring Anwendung auch.

Definition im ApplicationContext

Wie gewohnt werden im ApplicationContext alle notwendigen Beans deklariert und verschaltet.

<bean id="calledObject" class="de.lusiardi.quartzdemo.CalledService"/>
<bean id="pollerJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject" ref="pollerObject"/>
    <property name="targetMethod" value="calledMethod"/>
</bean>
<bean id="pollerTrigger20s" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
    <property name="jobDetail" ref="pollerJob"/>
    <property name="startDelay" value="10000"/>
    <property name="repeatInterval" value="20000"/>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="pollerTrigger20s"/>
        </list>
    </property>
</bean>

Zunächst wird unter der Id calledObject eine Instanz der Klasse angelegt, die unsere aufzurufende Methode beinhaltet. Anschließend wird ein Job unter der Id pollerJob vom Typ MethodInvokingJobDetailFactoryBean angelegt. Hier wird festgelegt, welche Methode der Bean mit der Id calledObject aufgerufen wird. Die Bean mit Id pollerTrigger20s vom Typ SimpleTriggerBean wird nun festgelegt, dass der pollerJob nach einer Verzögerung von 10s alle 20s laufen soll. Die Angaben der Zeiten sind in Milisekunden. Abschließend werden über eine SchedulerFactoryBean alle Trigger aktiviert. Hier ist es nur der pollerTrigger20s.

Resumé

Hat man die Klippe der inkompatiblen Funktionen umschifft, so erhält man eine saubere Methode um regelmässige Aufgaben innerhalb der Java-Applikation zu lösen. Dabei  spielt sich der größte Teil der Konfiguration im ApplicationContext ab.

Dieser Ansatz bietet gegenüber den klassischen Cronjobs einige Vorteile:

  • Die Aufgaben können direkt in der Applikation entwickelt werden
  • Keine Konfiguration für Cron ausserhalb der Applikation, die vergessen werden könnte
  • Keine zusätzliche Startup-Time für JVM zum Ausführen von Java-Jobs