Quartz Basic Concepts
Quartz is a task scheduling framework that is mainly used to trigger the execution of a task at a specific time.
The core concepts of Quartz
Scheduler (Scheduler): responsible for task scheduling and management, including task start, pause, resume and other operations.
Task (Job): you need to implement the interface execute method, which defines the specific execution logic of the task.
Trigger (Trigger): defines the trigger conditions for task execution , including simple trigger (SimpleTrigger) and cron trigger (CronTrigger).
Task details (JobDetail): used to define the details of the task , such as task name , group name and so on.
JobBuilder and TriggerBuilder: used to define and build instances of tasks and triggers.
ThreadPool: used to schedule the execution of each job in parallel to improve efficiency.
Listeners (Listener): including task listeners, trigger listeners and scheduler listeners, used to listen to the task and trigger state changes.
The basic steps for using Quartz
Create a task class: implement the execute method of the Job interface to define the execution logic of the task.
Generate task details (JobDetail): through the JobBuilder to define the details of the task.
Generate triggers (Trigger): TriggerBuilder through the definition of the task trigger conditions , you can choose to use a simple trigger or cron trigger .
Get Scheduler (Scheduler): through the SchedulerFactory to create scheduler objects , and will be bound to the task and trigger to start the scheduler .
Pros and Cons of Quartz
Pros: support for complex scheduling needs , including timing , repeated execution , concurrent execution , etc.; provides a rich API and tool class , easy to use and maintain ; support for Spring integration , easy to apply in the Spring project .
Cons: complex configuration , requires some learning costs ; for simple timed tasks , the use of Quartz may be too complex .
Integration with SpringBoot
Step 1: Add a dependency
<dependency> <groupId></groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
Step 2: Create the scheduler
package ; import ; import ; import ; import ; import ; import ; @Configuration public class QuartzConfig { @Bean public Scheduler scheduler() throws SchedulerException { SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory(); return (); } }
Step 3: Create Job
import ; import .slf4j.Slf4j; import ; import ; import ; import ; import ; import ; @Slf4j @Component public class MyJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { JobDataMap jobDataMap = ().getJobDataMap(); ("join:{}", ()); ("Time to perform timed tasks:{}", (new Date())); } }
Step 4: Create a task information class
import ; @Data public class JobInfo { private Long jobId; private String cronExpression; private String businessId; }
Step 5: Create JobDetail and trigger creation wrapper classes
import ; import ; import .*; import ; public class QuartzBuilder { public static final String RUN_CRON ="Timed execution"; public static final String RUN_ONE ="Execute once."; private static final String JOB_NAME_PREFIX ="flow"; public static final String TRIGGER_NAME_PREFIX ="trigger."; public static JobDetail createJobDetail(JobInfo jobInfo, String type){ String jobKey =JOB_NAME_PREFIX + (); if (RUN_ONE.equals(type)){ jobKey = JOB_NAME_PREFIX + new Date().getTime(); } return (MyJob.class) .withIdentity(jobKey,"my_group") .usingJobData("businessId",()) .usingJobData("businessType","Other parameters") .storeDurably().build(); } public static Trigger createTrigger(JobDetail jobDetail, JobInfo jobInfo){ return () .forJob(jobDetail) .withIdentity(TRIGGER_NAME_PREFIX + (),RUN_CRON) .withSchedule((())) .build(); } }
Step 6: The control layer interface implements the interfaces (execute once, start a timer, pause a task)
import ; import ; import .slf4j.Slf4j; import .*; import ; import ; import ; import ; @RestController @Slf4j public class QuartzController { @Autowired private Scheduler scheduler; /** * :: Timed task execution (one time only) *@return */ @GetMapping("runOne") public String runOne(){ JobInfo jobInfo = new JobInfo(); (1L); ("123"); ("0/5 * * * * ?"); JobDetail jobDetail = (jobInfo, QuartzBuilder.RUN_ONE); Trigger trigger = () .forJob(jobDetail) .startNow() .withSchedule(().withRepeatCount(0)) .build(); try { (jobDetail, trigger); if (!()) { (); } } catch (SchedulerException e) { (()); return "Execution failed."; } return "Implementation successful."; } /** * :: Commencement of timed execution *@return Implementation results */ @GetMapping("start") public String start() { try { JobInfo jobInfo = new JobInfo(); (1L); ("123"); ("0/5 * * * * ?"); TriggerKey triggerKey = new TriggerKey(QuartzBuilder.TRIGGER_NAME_PREFIX + (),QuartzBuilder.RUN_CRON); if ((triggerKey)) { (triggerKey); } else { JobDetail jobDetail = (jobInfo, QuartzBuilder.RUN_CRON); Trigger trigger = (jobDetail, jobInfo); (jobDetail, trigger); if (!()) { (); } } } catch (SchedulerException e) { (()); return "Execution failed."; } return "Implementation successful."; } /** * :: Discontinuation of mandate implementation *@return Implementation results */ @GetMapping("pause") public String pause() { try { JobInfo jobInfo = new JobInfo(); (1L); ("123"); ("0/5 * * * * ?"); TriggerKey triggerKey = new TriggerKey(QuartzBuilder.TRIGGER_NAME_PREFIX + (), QuartzBuilder.RUN_CRON); if ((triggerKey)) { (triggerKey); } } catch (SchedulerException e) { (()); return "Execution failed."; } return "Implementation successful."; } /** * :: Querying tasks in their activated state and then re-executing them */ @PostConstruct public void init(){ ("Query tasks in the started state and re-execute them."); start(); } }
Finally access the interface:
http://localhost:8080/runOne
http://localhost:8080/start
http://localhost:8080/pause
The normal steps should look like this.
1, the creation of the task recorded in the task table job_info, at this time the initial state is 0
2. Update the status of the task table when starting a task to 1
3, if the application is closed, then the next time the application is started, you need to start the task with a status of 1 as well, so you don't need to think about tuning the interface to start again.