Inleiding tot kwarts

1. Overzicht

Kwarts is een open source raamwerk voor taakplanning dat volledig in Java is geschreven en is ontworpen voor gebruik in beide J2SE en J2EE toepassingen. Het biedt een grote flexibiliteit zonder aan eenvoud in te boeten.

U kunt complexe schema's maken voor het uitvoeren van elke taak. Voorbeelden zijn b.v. taken die dagelijks worden uitgevoerd, elke andere vrijdag om 19.30 uur. of alleen op de laatste dag van elke maand.

In dit artikel zullen we elementen bekijken om een ​​baan te bouwen met de Quartz API. Voor een kennismaking in combinatie met Spring raden we aan Spring in te plannen met Quartz.

2. Maven afhankelijkheden

We moeten de volgende afhankelijkheid toevoegen aan het pom.xml:

 org. kwarts-planner kwarts 2.3.0 

De nieuwste versie is te vinden in de Maven Central-repository.

3. De Quartz API

Het hart van het framework is het Planner. Het is verantwoordelijk voor het beheer van de runtime-omgeving voor onze applicatie.

Om schaalbaarheid te garanderen, is Quartz gebaseerd op een multi-threaded architectuur. Wanneer het is gestart, initialiseert het framework een set werkthreads die worden gebruikt door de Planner uitvoeren Jobs.

Dit is hoe het framework veel kan draaien Jobs gelijktijdig. Het is ook afhankelijk van een losjes gekoppelde set ThreadPool beheercomponenten voor het beheer van de threadomgeving.

De belangrijkste interfaces van de API zijn:

  • Planner - de primaire API voor interactie met de planner van het framework
  • Baan - een interface die moet worden geïmplementeerd door componenten die we willen laten uitvoeren
  • JobDetail - gebruikt om instanties van te definiëren Jobs
  • Op gang brengen - een onderdeel dat de planning bepaalt waarop een gegeven Job zal worden uitgevoerd
  • JobBuilder - gebruikt om te bouwen JobDetail instanties, die instanties van Jobs
  • TriggerBuilder - gebruikt om te bouwen Op gang brengen gevallen

Laten we elk van deze componenten eens bekijken.

4. Planner

Voordat we het Planner, het moet worden geïnstantieerd. Hiervoor kunnen we de fabriek gebruiken SchedulerFactory:

SchedulerFactory schedulerFactory = nieuwe StdSchedulerFactory (); Scheduler scheduler = schedulerFactory.getScheduler ();

EEN PlannerDe levenscyclus wordt begrensd door de creatie ervan, via een SchedulerFactory en een oproep aan zijn afsluiten() methode. Zodra het Planner interface kan worden gebruikt om toe te voegen, te verwijderen en te vermelden Jobs en Triggersen voer andere planningsgerelateerde bewerkingen uit (zoals het pauzeren van een trigger).

Echter, de Planner zal niet reageren op triggers totdat het is gestart met de begin() methode:

planner.start ();

5. Banen

EEN Job is een klasse die de Job koppel. Het heeft maar één eenvoudige methode:

public class SimpleJob implementeert Job {public void execute (JobExecutionContext arg0) gooit JobExecutionException {System.out.println ("Dit is een quartz job!"); }}

Wanneer de Job's trigger-branden, de uitvoeren () methode wordt aangeroepen door een van de werkthreads van de planner.

De JobExecutionContext object dat aan deze methode wordt doorgegeven, voorziet de taakinstantie van informatie over de runtime-omgeving, een handle naar de Planner die het heeft uitgevoerd, een handvat naar de Op gang brengen dat leidde tot de uitvoering, de taak JobDetail object en een paar andere items.

De JobDetail object is gemaakt door de Quartz-client op het moment dat het Job wordt toegevoegd aan de Planner. Het is in wezen de definitie van de taakinstantie:

JobDetail job = JobBuilder.newJob (SimpleJob.class) .withIdentity ("myJob", "group1") .build ();

Dit object kan ook verschillende eigenschapsinstellingen bevatten voor de Job, evenals een JobDataMap, die kan worden gebruikt om statusinformatie op te slaan voor een bepaald exemplaar van onze jobklasse.

5.1. JobDataMap

De JobDataMap wordt gebruikt om elke hoeveelheid data-objecten te bewaren die we beschikbaar willen stellen aan de taakinstantie wanneer deze wordt uitgevoerd. JobDataMap is een implementatie van de Java Kaart interface en heeft enkele extra gemaksmethoden voor het opslaan en ophalen van gegevens van primitieve typen.

Hier is een voorbeeld van het plaatsen van gegevens in het JobDataMap tijdens het bouwen van de JobDetail, voordat u de taak aan de planner toevoegt:

JobDetail job = newJob (SimpleJob.class) .withIdentity ("myJob", "group1") .usingJobData ("jobSays", "Hallo wereld!") .UsingJobData ("myFloatValue", 3.141f) .build ();

En hier is een voorbeeld van hoe u toegang kunt krijgen tot deze gegevens tijdens de uitvoering van de taak:

openbare klasse SimpleJob implementeert Job {public void execute (JobExecutionContext context) gooit JobExecutionException {JobDataMap dataMap = context.getJobDetail (). getJobDataMap (); String jobSays = dataMap.getString ("jobSays"); zweven myFloatValue = dataMap.getFloat ("myFloatValue"); System.out.println ("Job zegt:" + jobSays + ", en val is:" + myFloatValue); }}

In het bovenstaande voorbeeld wordt afgedrukt "Job zegt Hallo wereld! En waarde is 3,141".

We kunnen ook setter-methoden aan onze jobklasse toevoegen die overeenkomen met de namen van sleutels in de JobDataMap.

Als we dit doen, is de standaard van Quartz JobFactory implementatie roept automatisch die setters op wanneer de taak wordt geïnstantieerd, waardoor de noodzaak wordt voorkomen om de waarden expliciet uit de kaart te halen binnen onze execute-methode.

6. Triggers

Op gang brengen objecten worden gebruikt om de uitvoering van Jobs.

Wanneer we een Job, moeten we een trigger instantiëren en de eigenschappen ervan aanpassen om onze planningsvereisten te configureren:

Trigger trigger = TriggerBuilder.newTrigger () .withIdentity ("myTrigger", "group1") .startNow () .withSchedule (SimpleScheduleBuilder.simpleSchedule () .withIntervalInSeconds (40) .repeatForever ()) .build ();

EEN Op gang brengen kan ook een JobDataMap ermee geassocieerd. Dit is handig voor het doorgeven van parameters aan een Job die specifiek zijn voor de uitvoeringen van de trigger.

Er zijn verschillende soorten triggers voor verschillende planningsbehoeften. Elk heeft verschillende TriggerKey eigenschappen voor het volgen van hun identiteit. Enkele andere eigenschappen zijn echter gemeenschappelijk voor alle triggertypen:

  • De jobKey eigenschap geeft de identiteit aan van de taak die moet worden uitgevoerd wanneer de trigger wordt geactiveerd.
  • De starttijd eigenschap geeft aan wanneer het schema van de trigger voor het eerst van kracht wordt. De waarde is a java.util.Date object dat een moment in de tijd definieert voor een bepaalde kalenderdatum. Voor sommige triggertypen wordt de trigger op de opgegeven starttijd geactiveerd. Voor anderen geeft het gewoon de tijd aan waarop het schema moet beginnen.
  • De eindtijd eigenschap geeft aan wanneer het schema van de trigger moet worden geannuleerd.

Quartz wordt geleverd met een handvol verschillende triggertypes, maar de meest gebruikte zijn SimpleTrigger en CronTrigger.

6.1. Prioriteit

Soms, als we veel triggers hebben, heeft Quartz misschien niet genoeg middelen om onmiddellijk alle taken te ontslaan die op hetzelfde moment zijn gepland. In dit geval willen we misschien bepalen welke van onze triggers als eerste beschikbaar wordt. Dit is precies wat de prioriteit eigenschap op een trigger wordt gebruikt voor.

Bijvoorbeeld, wanneer tien triggers tegelijkertijd worden geactiveerd en er slechts vier worker-threads beschikbaar zijn, worden de eerste vier triggers met de hoogste prioriteit als eerste uitgevoerd. Als we geen prioriteit instellen voor een trigger, gebruikt deze een standaardprioriteit van vijf. Elke gehele waarde is toegestaan ​​als prioriteit, positief of negatief.

In het onderstaande voorbeeld hebben we twee triggers met een verschillende prioriteit. Als er niet genoeg bronnen zijn om alle triggers tegelijkertijd te activeren, triggerA zal de eerste zijn die wordt ontslagen:

Trigger triggerA = TriggerBuilder.newTrigger () .withIdentity ("triggerA", "group1") .startNow () .withPriority (15) .withSchedule (SimpleScheduleBuilder.simpleSchedule () .withIntervalInSeconds (40) .repeatForever ()) .build ()). ; Trigger triggerB = TriggerBuilder.newTrigger () .withIdentity ("triggerB", "group1") .startNow () .withPriority (10) .withSchedule (SimpleScheduleBuilder.simpleSchedule () .withIntervalInSeconds (20) .repeatForever ()) .build ()). ;

6.2. Misfire-instructies

Een misfire treedt op als een aanhoudende trigger mist zijn vuurtijd vanwege de Planner wordt afgesloten, of in het geval dat er geen beschikbare threads zijn in de threadpool van Quartz.

Voor de verschillende triggertypen zijn verschillende instructies voor het ontsteken beschikbaar. Standaard gebruiken ze een slimme beleidsinstructie. Wanneer de planner start, zoekt deze naar blijvende triggers die zijn mislukt. Daarna worden ze allemaal bijgewerkt op basis van hun individueel geconfigureerde instructies voor ontstekingsfouten.

Laten we de onderstaande voorbeelden eens bekijken:

Trigger misFiredTriggerA = TriggerBuilder.newTrigger () .startAt (DateUtils.addSeconds (nieuwe datum (), -10)) .build (); Trigger misFiredTriggerB = TriggerBuilder.newTrigger () .startAt (DateUtils.addSeconds (nieuwe datum (), -10)) .withSchedule (SimpleScheduleBuilder.simpleSchedule () .withMisfireHandlingInstructionFireNow ()) .build ();

We hebben gepland dat de trigger 10 seconden geleden wordt uitgevoerd (dus het is 10 seconden te laat tegen de tijd dat deze is gemaakt) om een ​​mislukking te simuleren, bijv. omdat de planner niet beschikbaar was of niet voldoende werkthreads beschikbaar had. In een realistisch scenario zouden we natuurlijk nooit triggers op deze manier plannen.

In de eerste trigger (misFiredTriggerA) er zijn geen instructies voor het behandelen van ontstekingsfouten ingesteld. Vandaar een oproep slim beleid wordt in dat geval gebruikt en heet: withMisfireHandlingInstructionFireNow (). Dit betekent dat de taak onmiddellijk wordt uitgevoerd nadat de planner de misfire ontdekt.

De tweede trigger definieert expliciet wat voor soort gedrag we verwachten als er sprake is van mislukking. In dit voorbeeld is het toevallig hetzelfde slimme beleid.

6.3. SimpleTrigger

SimpleTrigger wordt gebruikt voor scenario's waarin we op een bepaald moment een taak moeten uitvoeren. Dit kan exact één keer zijn of herhaaldelijk met specifieke tussenpozen.

Een voorbeeld zou kunnen zijn om een ​​taakuitvoering om precies 12:20:00 uur op 13 januari 2018 af te vuren. Evenzo kunnen we op dat tijdstip beginnen, en dan nog vijf keer, elke tien seconden.

In onderstaande code staat de datum myStartTime is eerder gedefinieerd en wordt gebruikt om een ​​trigger voor een bepaald tijdstempel te bouwen:

SimpleTrigger-trigger = (SimpleTrigger) TriggerBuilder.newTrigger () .withIdentity ("trigger1", "group1") .startAt (myStartTime) .forJob ("job1", "group1") .build ();

Laten we vervolgens een trigger bouwen voor een specifiek moment in de tijd, en dan elke tien seconden tien keer herhalen:

SimpleTrigger-trigger = (SimpleTrigger) TriggerBuilder.newTrigger () .withIdentity ("trigger2", "group1") .startAt (myStartTime) .withSchedule (simpleSchedule () .withIntervalInSeconds (10) .withRepeatCount (10)) .forJob ("job1" ) .build ();

6.4. CronTrigger

De CronTrigger wordt gebruikt wanneer we planningen nodig hebben op basis van kalenderachtige uitspraken. We kunnen bijvoorbeeld schietschema's specificeren zoals elke vrijdag om 12.00 uur of elke weekdag om 9.30 uur.

Cron-expressies worden gebruikt om instanties van CronTrigger. Deze uitdrukkingen bestaan ​​uit Snaren die zijn opgebouwd uit zeven subuitdrukkingen. We kunnen hier meer lezen over Cron-Expressions.

In het onderstaande voorbeeld bouwen we een trigger die elke dag om de minuut tussen 8.00 en 17.00 uur wordt geactiveerd:

CronTrigger-trigger = TriggerBuilder.newTrigger () .withIdentity ("trigger3", "group1") .withSchedule (CronScheduleBuilder.cronSchedule ("0 0/2 8-17 * *?")) .ForJob ("myJob", "group1" ) .build ();

7. Conclusie

In dit artikel hebben we laten zien hoe u een Planner om een Job. We hebben ook enkele van de meest gebruikte triggeropties gezien: SimpleTrigger en CronTrigger.

Quartz kan worden gebruikt om eenvoudige of complexe schema's te maken voor het uitvoeren van tientallen, honderden of zelfs meer taken. Meer informatie over het raamwerk is te vinden op de hoofdwebsite.

De broncode van de voorbeelden is te vinden op GitHub.