Planning in het voorjaar met Quartz

1. Overzicht

In deze tutorial bouwen we een simple Planner in het voorjaar met kwarts.

We beginnen met een eenvoudig doel voor ogen: eenvoudig een nieuwe geplande taak configureren.

1.1. Sleutelcomponenten van de Quartz API

Quartz heeft een modulaire architectuur. Het bestaat uit verschillende basiscomponenten die naar wens kunnen worden gecombineerd. In deze tutorial zullen we ons concentreren op degene die voor elke taak gelden: Job, JobDetail, Op gang brengen enPlanner.

Hoewel we Spring zullen gebruiken om de applicatie te beheren, kan elk afzonderlijk onderdeel op twee manieren worden geconfigureerd: het Kwarts manier of de Voorjaar manier (met behulp van de gemaksklassen).

We zullen beide volledigheidshalve behandelen, maar beide kunnen worden overgenomen. Laten we beginnen met bouwen, één onderdeel tegelijk.

2. Job en JobDetail

2.1. Job

De API biedt een Job interface met slechts één methode - uitvoeren. Het moet worden geïmplementeerd door de klasse die het eigenlijke werk bevat dat moet worden gedaan, d.w.z. de taak. Wanneer de trigger van een taak wordt geactiveerd, roept de planner het uitvoeren methode, het doorgeven van een JobExecutionContext voorwerp.

De JobExecutionContext geeft de taakinstantie informatie over zijn runtime-omgeving, inclusief een ingang voor de planner, een ingang voor de trigger en de taak JobDetail voorwerp.

In dit korte voorbeeld delegeert de taak de taak naar een serviceklasse:

@Component openbare klasse SampleJob implementeert Job {@Autowired privé SampleJobService jobService; public void execute (JobExecutionContext context) gooit JobExecutionException {jobService.executeSampleJob (); }} 

2.2. JobDetail

Hoewel de job het werkpaard is, slaat Quartz geen daadwerkelijke instantie van de jobklasse op. In plaats daarvan kunnen we een instantie van de Job de ... gebruiken JobDetail klasse. De klasse van de baan moet worden verstrekt aan de JobDetail zodat het de type van de uit te voeren taak.

2.3. Kwarts JobBuilder

Het kwarts JobBuilder biedt een bouwer-stijl API voor het construeren van JobDetail entiteiten.

@Bean openbare JobDetail jobDetail () {retourneer JobBuilder.newJob (). OfType (SampleJob.class) .storeDurably () .withIdentity ("Qrtz_Job_Detail") .withDescription ("Roep Sample Job-service op ...") .build (); }

2.4. Voorjaar JobDetailFactoryBean

Lente JobDetailFactoryBean biedt bean-style gebruik voor het configureren JobDetail gevallen. Het gebruikt de Spring bean-naam als de taaknaam, tenzij anders gespecificeerd:

@Bean openbaar JobDetailFactoryBean jobDetail () {JobDetailFactoryBean jobDetailFactory = nieuwe JobDetailFactoryBean (); jobDetailFactory.setJobClass (SampleJob.class); jobDetailFactory.setDescription ("Roep Sample Job-service op ..."); jobDetailFactory.setDurability (true); terug jobDetailFactory; }

Een nieuw exemplaar van JobDetail wordt gemaakt voor elke uitvoering van de taak. De JobDetail object geeft de gedetailleerde eigenschappen van de taak weer. Zodra de uitvoering is voltooid, worden verwijzingen naar de instantie verwijderd.

3. Trigger

EEN Op gang brengen is het mechanisme om een Job, d.w.z. een Op gang brengen instantie "vuurt" de uitvoering van een taak. Er is een duidelijke scheiding van verantwoordelijkheden tussen de Job (notie van taak) en Op gang brengen (planningsmechanisme).

In aanvulling op Job, heeft de trigger ook een type die kan worden gekozen op basis van de planningseisen.

Laten we zeggen dat we onze taak willen plannen om uit te voeren een keer per uur, voor onbepaalde tijd - we kunnen Quartz's gebruiken TriggerBuilder of lente SimpleTriggerFactoryBean om dat te doen.

3.1. Kwarts TriggerBuilder

TriggerBuilder is een bouwer-stijl API voor het construeren van de Op gang brengen entiteit:

@Bean openbare trigger-trigger (JobDetail-taak) {return TriggerBuilder.newTrigger (). ForJob (job) .withIdentity ("Qrtz_Trigger") .withDescription ("Voorbeeldtrigger") .withSchedule (simpleSchedule (). RepeatForever (). WithIntervalInHours (1 )). build (); }

3.2. Voorjaar SimpleTriggerFactoryBean

SimpleTriggerFactoryBean biedt bean-style gebruik voor het configureren SimpleTrigger. Het gebruikt de Spring bean-naam als de triggernaam en is standaard ingesteld op onbepaalde herhaling, tenzij anders gespecificeerd:

@Bean openbare SimpleTriggerFactoryBean-trigger (JobDetail-taak) {SimpleTriggerFactoryBean-trigger = nieuwe SimpleTriggerFactoryBean (); trigger.setJobDetail (taak); trigger.setRepeatInterval (3600000); trigger.setRepeatCount (SimpleTrigger.REPEAT_INDEFINITELY); terugkeer trigger; }

4. Configureren van het JobStore

JobStore biedt het opslagmechanisme voor de Job en Op gang brengen, en is verantwoordelijk voor het bijhouden van alle gegevens die relevant zijn voor de taakplanner. De API ondersteunt beide in het geheugen en aanhoudend winkels.

4.1. In het geheugen JobStore

We zullen bijvoorbeeld het in-memory gebruiken RAMJobStore die razendsnelle prestaties en eenvoudige configuratie biedt via quartz.eigenschappen:

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

Het voor de hand liggende nadeel van de RAMJobStore is dat het is vluchtig in de natuur. Alle planningsinformatie gaat verloren tussen het afsluiten. Als taakdefinities en -schema's tussen shutdowns moeten worden bewaard, blijft het persistent JDBCJobStore moet in plaats daarvan worden gebruikt.

Om een ​​in-memory JobStore in de lente, we zetten deze eigenschap in onze application.properties:

spring.quartz.job-store-type = geheugen

4.2. JDBC JobStore

Er zijn twee soorten JDBCJobStore: JobStoreTX en JobStoreCMT. Ze doen allebei hetzelfde werk: het opslaan van planningsinformatie in een database.

Het verschil tussen de twee is hoe ze de transacties beheren die de gegevens vastleggen. De JobStoreCMT type vereist een applicatietransactie om gegevens op te slaan, terwijl de JobStoreTX type start en beheert zijn eigen transacties.

Er zijn verschillende eigenschappen om in te stellen voor een JDBCJobStore. We moeten minimaal het type JDBCJobStore, de gegevensbron en de klasse van het databasestuurprogramma. Er zijn stuurprogrammaklassen voor de meeste databases, maar StdJDBCDelegate dekt de meeste gevallen:

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

Het opzetten van een JDBC JobStore in Spring neemt een paar stappen. Ten eerste stellen we het winkeltype in onze application.properties:

spring.quartz.job-store-type = jdbc

Vervolgens moeten we automatische configuratie inschakelen en Spring de gegevensbron geven die de Quartz-planner nodig heeft. De @QuartzDataSource annotation doet het harde werk bij het configureren en initialiseren van de Quartz-database voor ons:

@Configuration @EnableAutoConfiguration openbare klasse SpringQrtzScheduler {@Bean @QuartzDataSource openbare gegevensbron quartzDataSource () {retourneer DataSourceBuilder.create (). Build (); }}

5. Planner

De Planner interface is de belangrijkste API voor interactie met de taakplanner.

EEN Planner kan worden geïnstantieerd met een SchedulerFactory. Eenmaal gemaakt, Jobs en Op gang brengens kunnen ermee worden geregistreerd. Aanvankelijk was het Planner staat in de modus "stand-by", en zijn begin methode moet worden aangeroepen om de threads te starten die de uitvoering van taken activeren.

5.1. Kwarts StdSchedulerFactory

Door simpelweg het getScheduler methode op de StdSchedulerFactory, kunnen we de Planner, initialiseer het (met de geconfigureerde JobStore en ThreadPool), en retourneer een handle naar zijn API:

@Bean openbare Scheduler-planner (Trigger-trigger, JobDetail-taak, SchedulerFactoryBean-fabriek) genereert SchedulerException {Scheduler scheduler = factory.getScheduler (); scheduler.scheduleJob (taak, trigger); planner.start (); terugkeer planner; }

5.2. Voorjaar SchedulerFactoryBean

Lente SchedulerFactoryBean biedt bean-style gebruik voor het configureren van een Planner, beheert zijn levenscyclus binnen de toepassingscontext en stelt de Planner als boon voor injectie met afhankelijkheid:

@Bean openbare SchedulerFactoryBean scheduler (Trigger-trigger, JobDetail-taak, DataSource quartzDataSource) {SchedulerFactoryBean schedulerFactory = nieuwe SchedulerFactoryBean (); schedulerFactory.setConfigLocation (nieuwe ClassPathResource ("quartz.properties")); schedulerFactory.setJobFactory (springBeanJobFactory ()); schedulerFactory.setJobDetails (taak); schedulerFactory.setTriggers (trigger); schedulerFactory.setDataSource (quartzDataSource); terugkeer schedulerFactory; }

5.3. Configureren SpringBeanJobFactory

De SpringBeanJobFactory biedt ondersteuning voor het injecteren van de plannercontext, taakgegevenskaart en trigger-gegevensinvoer als eigenschappen in de taakbeane tijdens het maken van een instantie.

Het ontbreekt echter aan ondersteuning voor het injecteren van bonenreferenties vanuit de toepassingscontext. Dankzij de auteur van deze blogpost kunnen we toevoegen automatische bedrading steun aan SpringBeanJobFactory zo:

@Bean openbaar SpringBeanJobFactory springBeanJobFactory () {AutoWiringSpringBeanJobFactory jobFactory = nieuwe AutoWiringSpringBeanJobFactory (); jobFactory.setApplicationContext (applicationContext); terug jobFactory; }

6. Conclusie

Dat is alles. We hebben zojuist onze eerste basisplanner gebouwd met behulp van de Quartz API en de gemaksklassen van Spring.

De belangrijkste uitkomst van deze tutorial is dat we een taak konden configureren met slechts een paar regels code en zonder enige XML-gebaseerde configuratie.

Het complete broncode voor het voorbeeld is beschikbaar in dit github-project. Het is een Maven-project dat kan worden geïmporteerd en uitgevoerd zoals het is. De standaardinstelling maakt gebruik van de gemaksklassen van Spring, die gemakkelijk kunnen worden omgeschakeld naar Quartz API met een run-time parameter (raadpleeg de README.md in de repository).