Planung im Frühjahr mit Quarz

Scheduling im Frühjahr mit Quarz

1. Überblick

In diesem Tutorial erstellen wir ein einfachesScheduler in Spring with Quartz.

Wir beginnen mit einem einfachen Ziel - der einfachen Konfiguration eines neuen geplanten Jobs.

1.1. Schlüsselkomponenten der Quarz-API

Quarz hat eine modulare Architektur. Es besteht aus mehreren Grundkomponenten, die beliebig kombiniert werden können. In diesem Tutorial konzentrieren wir uns auf diejenigen, die jedem Job gemeinsam sind:Job,JobDetail,Trigger undScheduler.

Obwohl wir Spring zum Verwalten der Anwendung verwenden werden, kann jede einzelne Komponente auf zwei Arten konfiguriert werden: auf die Weise vonQuartzoder auf die Weise vonSpring(unter Verwendung ihrer Komfortklassen).

Wir werden der Vollständigkeit halber beides so weit wie möglich behandeln, aber es kann auch beides verabschiedet werden. Beginnen wir mit dem Bau einer Komponente nach der anderen.

Weitere Lektüre:

Eine Anleitung zum Spring Task Scheduler

Eine schnelle und praktische Anleitung zur Planung im Frühjahr mit dem Taskplaner

Read more

Scheduling in Java EE

Eine Demonstration zum Planen von Aufgaben in Java EE mit der @ Schedule-Annotation und dem Zeitgeberdienst.

Read more

Einführung in Drools

Erfahren Sie, wie Sie Drools als Business Rule Management System (BRMS) verwenden.

Read more

2. Job undJobDetail

2.1. Job

Die API stellt eineJob-Schnittstelle mit nur einer Methode bereit -execute.. Sie muss von der Klasse implementiert werden, die die tatsächlich auszuführende Arbeit enthält, d. H. die Aufgabe. Wenn der Trigger eines Jobs ausgelöst wird, ruft der Scheduler die Methodeexecuteauf und übergibt ihm ein ObjektJobExecutionContext.

JobExecutionContext liefert der Jobinstanz Informationen zu ihrer Laufzeitumgebung, einschließlich eines Handles für den Scheduler, eines Handles für den Trigger und desJobDetail-Objekts des Jobs.

In diesem kurzen Beispiel delegiert der Job die Aufgabe an eine Serviceklasse: __

@Component
public class SampleJob implements Job {

    @Autowired
    private SampleJobService jobService;

    public void execute(JobExecutionContext context) throws JobExecutionException {
        jobService.executeSampleJob();
    }
}

2.2. JobDetail

Während der Job das Arbeitstier ist, speichert Quartz keine tatsächliche Instanz der Jobklasse. Stattdessen können wir eine Instanz derJob mithilfe derJobDetail-Klasse definieren. Die Klasse des Jobs muss denJobDetail bereitgestellt werden, damit sie dietype des auszuführenden Jobs kennt.

2.3. QuarzJobBuilder

Das QuartzJobBuilder bietet eine API im Builder-Stil zum Erstellen vonJobDetail-Entitäten.

@Bean
public JobDetail jobDetail() {
    return JobBuilder.newJob().ofType(SampleJob.class)
      .storeDurably()
      .withIdentity("Qrtz_Job_Detail")
      .withDescription("Invoke Sample Job service...")
      .build();
}

2.4. FederJobDetailFactoryBean

JobDetailFactoryBeanvon Spring bietet eine Verwendung im Bean-Stil zum Konfigurieren der Instanzen vonJobDetail. Sofern nicht anders angegeben, wird der Name des Spring Beans als Auftragsname verwendet:

@Bean
public JobDetailFactoryBean jobDetail() {
    JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
    jobDetailFactory.setJobClass(SampleJob.class);
    jobDetailFactory.setDescription("Invoke Sample Job service...");
    jobDetailFactory.setDurability(true);
    return jobDetailFactory;
}

Für jede Ausführung des Jobs wird eine neue Instanz vonJobDetail erstellt. Das ObjektJobDetailvermittelt die detaillierten Eigenschaften des Jobs. Sobald die Ausführung abgeschlossen ist, werden Verweise auf die Instanz gelöscht.

3. Auslösen

ATrigger ist der Mechanismus zum Planen vonJob, d.h. Die Instanz vonTrigger"löst" die Ausführung eines Jobs aus. Es gibt eine klare Trennung der Verantwortlichkeiten zwischenJob(Aufgabenbegriff) undTrigger(Planungsmechanismus).

Zusätzlich zuJob benötigt der Trigger auchtype, die basierend auf den Planungsanforderungen ausgewählt werden können.

Nehmen wir an, wir möchten unsere Aufgabe so planen, dassonce every hour,auf unbestimmte Zeit ausgeführt wird. Dazu können wirTriggerBuildervon Quartz oderSimpleTriggerFactoryBeanvon Spring verwenden.

3.1. QuarzTriggerBuilder

TriggerBuilder ist eine API im Builder-Stil zum Erstellen derTrigger-Entität:

@Bean
public Trigger trigger(JobDetail job) {
    return TriggerBuilder.newTrigger().forJob(job)
      .withIdentity("Qrtz_Trigger")
      .withDescription("Sample trigger")
      .withSchedule(simpleSchedule().repeatForever().withIntervalInHours(1))
      .build();
}

3.2. FederSimpleTriggerFactoryBean

SimpleTriggerFactoryBean bietet eine Verwendung im Bean-Stil zum Konfigurieren vonSimpleTrigger. Es verwendet den Spring Bean-Namen als Triggernamen und verwendet standardmäßig eine unbestimmte Wiederholung, sofern nicht anders angegeben:

@Bean
public SimpleTriggerFactoryBean trigger(JobDetail job) {
    SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
    trigger.setJobDetail(job);
    trigger.setRepeatInterval(3600000);
    trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
    return trigger;
}

4. JobStorekonfigurieren s

JobStore stellt den Speichermechanismus fürJob undTrigger bereit und ist für die Verwaltung aller für den Job Scheduler relevanten Daten verantwortlich. Die API unterstützt sowohlin-memory als auchpersistent Speicher.

4.1. In-MemoryJobStore

Zum Beispiel werden wir den speicherinternenRAMJobStore verwenden, der eine blitzschnelle Leistung und einfache Konfiguration überquartz.properties bietet:

org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore

Der offensichtliche Nachteil vonRAMJobStore besteht darin, dass es sich umvolatile handelt. Alle Planungsinformationen gehen zwischen den Abschaltungen verloren. Wenn Jobdefinitionen und Zeitpläne zwischen dem Herunterfahren beibehalten werden müssen, müssen stattdessen die persistentenJDBCJobStore verwendet werden. Um ein In-MemoryJobStore in Spring, zu aktivieren, setzen wir diese Eigenschaft in unserenapplication.properties:

spring.quartz.job-store-type=memory

4.2. JDBCJobStore

Es gibt zwei Arten vonJDBCJobStore:JobStoreTX undJobStoreCMT. Beide erledigen die gleiche Aufgabe, um Planungsinformationen in einer Datenbank zu speichern.

Der Unterschied zwischen den beiden besteht darin, wie sie die Transaktionen verwalten, die die Daten festschreiben. Der TypJobStoreCMTerfordert eine Anwendungstransaktion zum Speichern von Daten, während der TypJobStoreTXeine eigenen Transaktionen startet und verwaltet.

FürJDBCJobStore müssen mehrere Eigenschaften festgelegt werden. Zumindest müssen wir den Typ vonJDBCJobStore, die Datenquelle und die Datenbanktreiberklasse angeben. Für die meisten Datenbanken gibt es Treiberklassen, aberStdJDBCDelegate deckt die meisten Fälle ab:

org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource=quartzDataSource

Das Einrichten eines JDBCJobStore im Frühjahr dauert einige Schritte. Zuerst setzen wir den Speichertyp inapplication.properties:

spring.quartz.job-store-type=jdbc

Als nächstes müssen wir die automatische Konfiguration aktivieren und Spring die vom Quartz-Scheduler benötigte Datenquelle geben. Die Annotation@QuartzDataSourceerledigt die harte Arbeit bei der Konfiguration und Initialisierung der Quartz-Datenbank für uns:

@Configuration
@EnableAutoConfiguration
public class SpringQrtzScheduler {

    @Bean
    @QuartzDataSource
    public DataSource quartzDataSource() {
        return DataSourceBuilder.create().build();
    }
}

5. Scheduler

DieScheduler-Schnittstelle ist die Haupt-API für die Schnittstelle zum Job Scheduler.

EinScheduler kann mit einemSchedulerFactory. instanziiert werden. Nach dem Erstellen könnenJobs undTriggers registriert werden. Zu Beginn befindet sichScheduler im Standby-Modus, und diestart-Methode muss aufgerufen werden, um die Threads zu starten, die die Ausführung von Jobs auslösen.

5.1. QuarzStdSchedulerFactory

Durch einfaches Aufrufen dergetScheduler-Methode fürStdSchedulerFactory können wir dieScheduler instanziieren, initialisieren (mit den konfiguriertenJobStore undThreadPool) und a zurückgeben Handle zu seiner API:

@Bean
public Scheduler scheduler(Trigger trigger, JobDetail job, SchedulerFactoryBean factory)
  throws SchedulerException {
    Scheduler scheduler = factory.getScheduler();
    scheduler.scheduleJob(job, trigger);
    scheduler.start();
    return scheduler;
}

5.2. FederSchedulerFactoryBean

SchedulerFactoryBeanvon Spring bietet eine Verwendung im Bean-Stil zum Konfigurieren vonScheduler, verwaltet seinen Lebenszyklus im Anwendungskontext und macht dieScheduler als Bean für die Abhängigkeitsinjektion verfügbar:

@Bean
public SchedulerFactoryBean scheduler(Trigger trigger, JobDetail job, DataSource quartzDataSource) {
    SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
    schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));

    schedulerFactory.setJobFactory(springBeanJobFactory());
    schedulerFactory.setJobDetails(job);
    schedulerFactory.setTriggers(trigger);
    schedulerFactory.setDataSource(quartzDataSource);
    return schedulerFactory;
}

5.3. SpringBeanJobFactory konfigurieren

SpringBeanJobFactory unterstützt das Einfügen des Schedulerkontexts, der Jobdatenzuordnung und das Auslösen von Dateneinträgen als Eigenschaften in die Job-Bean beim Erstellen einer Instanz.

Es fehlt jedoch die Unterstützung für das Injizieren von Bean-Referenzen ausapplication context. Dank des Autors vonthis blog post können wirauto-wiring wie folgt unterstützen:

@Bean
public SpringBeanJobFactory springBeanJobFactory() {
    AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory();
    jobFactory.setApplicationContext(applicationContext);
    return jobFactory;
}

6. Fazit

Das ist alles. Wir haben gerade unseren ersten Basisplaner mit der Quartz-API sowie den Convenience-Klassen von Spring erstellt.

Die wichtigste Erkenntnis aus diesem Tutorial ist, dass wir einen Job mit nur wenigen Codezeilen und ohne XML-basierte Konfiguration konfigurieren konnten.

Die vollständigensource code für das Beispiel sind inthis github project verfügbar. Es ist ein Maven-Projekt, das importiert und unverändert ausgeführt werden kann. Die Standardeinstellung verwendet die Convenience-Klassen von Spring, die mit einem Laufzeitparameter problemlos auf die Quartz-API umgestellt werden können (siehe README.md im Repository).